EFILib.Mod 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. MODULE EFILib; (** AUTHOR "Matthias Frei"; PURPOSE "EFI API"; *)
  2. IMPORT SYSTEM, EFI, EFIFileProtocol, EFISimpleFS, EFILoadedImage, Trace;
  3. TYPE Allocation = RECORD
  4. baseAddress: EFI.PhysicalAddress;
  5. numPages: EFI.Int;
  6. END;
  7. TYPE PtrToLongString = POINTER TO ARRAY 1024 OF EFI.Char16; (* to be able to use system.val etc.*)
  8. CONST
  9. maxAllocations = 128;
  10. VAR
  11. (* memory allocation *)
  12. allocations : ARRAY maxAllocations OF Allocation;
  13. numAllocations : LONGINT;
  14. (* argument parsing *)
  15. args : PtrToLongString;
  16. argLen : LONGINT;
  17. argPos : LONGINT;
  18. (* allocate memory pages. If addr = -1 (=FFFFFFFFFH) then a page at an arbitrary position will be allocated. *)
  19. PROCEDURE AllocateMemory*(VAR addr : EFI.PhysicalAddress; numPages : EFI.Int) : EFI.Status;
  20. VAR
  21. status : EFI.Status;
  22. allocationType : EFI.Int;
  23. BEGIN
  24. IF numAllocations < maxAllocations-1 THEN
  25. IF addr = -1 THEN
  26. allocationType := EFI.AllocateAnyPage;
  27. ELSE
  28. allocationType := EFI.AllocateAddress;
  29. END;
  30. status := EFI.table.BS.AllocatePages(allocationType, EFI.MTLoaderData, numPages, addr);
  31. IF status = EFI.Success THEN
  32. allocations[numAllocations].baseAddress := addr;
  33. allocations[numAllocations].numPages := numPages;
  34. INC(numAllocations);
  35. ELSE
  36. addr := 0;
  37. END;
  38. RETURN status;
  39. ELSE
  40. RETURN EFI.Error;
  41. END;
  42. END AllocateMemory;
  43. (* free all pages allocated by AllocateMemory *)
  44. PROCEDURE FreeMemory*;
  45. VAR
  46. status : EFI.Status;
  47. i : LONGINT;
  48. BEGIN
  49. FOR i := 0 TO numAllocations - 1 DO
  50. status := EFI.table.BS.FreePages(allocations[i].baseAddress, allocations[i].numPages);
  51. END;
  52. END FreeMemory;
  53. PROCEDURE GetMemoryMapping*(VAR adr: EFI.PhysicalAddress) : EFI.Status;
  54. CONST
  55. approxMemMapSize = 2048; (* we actually can not resize the buffer. just hope its enough *)
  56. VAR
  57. MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
  58. status : EFI.Status;
  59. MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
  60. MemMapElement : EFI.MemoryDescriptorPointer;
  61. i, numEntries : EFI.Int;
  62. hi, numcritEntries : HUGEINT;
  63. memsize : HUGEINT;
  64. tmp : EFI.PhysicalAddress;
  65. BEGIN
  66. MemMapSize := LEN(MemMap)*SIZEOF(EFI.MemoryDescriptor);
  67. status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
  68. IF status = EFI.ErrBufferTooSmall THEN
  69. (* we cant resize. We are doomed!*)
  70. RETURN status;
  71. END;
  72. adr := -1;
  73. TRACE(adr);
  74. status :=AllocateMemory(adr, 10); (* a few additional pages *)
  75. (* now bootTablePhAddr contains the base address of the allocated pages *)
  76. IF status # EFI.Success THEN
  77. RETURN status;
  78. END;
  79. numcritEntries := 0;
  80. MemMapSize := LEN(MemMap)*SIZEOF(EFI.MemoryDescriptor);
  81. status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
  82. IF status = EFI.ErrBufferTooSmall THEN
  83. (* we cant resize. We are doomed!*)
  84. RETURN status;
  85. END;
  86. numEntries := MemMapSize DIV DescriptorSize; (*DIV SIZEOF(EFI.MemoryDescriptor); *)
  87. tmp := 0H;
  88. memsize := 0;
  89. FOR i := 0 TO numEntries-1 DO
  90. MemMapElement := SYSTEM.VAL(EFI.MemoryDescriptorPointer, ADDRESSOF(MemMap[0])+i*DescriptorSize);
  91. (* IF (MemMapElement.Type # EFI.MTConventionalMemory *)
  92. IF ( (MemMapElement.Type = EFI.MTRuntimeServicesCode) OR ( MemMapElement.Type = EFI.MTRuntimeServicesData)
  93. OR (MemMapElement.Type = EFI.MTUnusableMemory) OR (MemMapElement.Type = EFI.MTACPIReclaimMemory)
  94. OR (MemMapElement.Type = EFI.MTACPIMemoryNVSM) OR (MemMapElement.Type = EFI.MTMemoryMappedIO)
  95. OR (MemMapElement.Type = EFI.MTMemoryMappedIOPortSpace) OR (MemMapElement.Type = EFI.MTPalCode)
  96. OR (MemMapElement.Type = EFI.MTLoaderCode) OR (MemMapElement.Type = EFI.MTLoaderData)
  97. OR (MemMapElement.Type = EFI.MTReserved)
  98. OR (MemMapElement.Type = EFI.MTBootServicesCode) OR (MemMapElement.Type = EFI.MTBootServicesData) (* this line shouldnt be - but it freezes if i touch that memory *)
  99. )THEN
  100. Trace.Address(ADDRESS(MemMapElement.PhysicalStart));
  101. Trace.String(" - " );
  102. Trace.Address(ADDRESS(MemMapElement.PhysicalStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize)));
  103. Trace.String(" X ");
  104. Trace.Address(ADDRESS(MemMapElement.VirtualStart));
  105. Trace.String(" - " );
  106. Trace.Address(ADDRESS(MemMapElement.VirtualStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize)));
  107. Trace.Ln;
  108. IF (tmp # MemMapElement.PhysicalStart) THEN
  109. SYSTEM.PUT(ADDRESS(adr+(numcritEntries*2+1+1)*8), MemMapElement.PhysicalStart);
  110. tmp := MemMapElement.PhysicalStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize);
  111. SYSTEM.PUT(ADDRESS(adr+(numcritEntries*2+1+1+1)*8), tmp);
  112. numcritEntries := numcritEntries +1;
  113. ELSE
  114. numcritEntries := numcritEntries -1;
  115. tmp := MemMapElement.PhysicalStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize);
  116. SYSTEM.PUT(ADDRESS(adr+(numcritEntries*2+1+1+1)*8), tmp);
  117. numcritEntries := numcritEntries +1;
  118. END;
  119. END;
  120. memsize := memsize + MemMapElement.NumberOfPages;
  121. END;
  122. FOR hi:= 0 TO numcritEntries-1 DO
  123. SYSTEM.GET(ADDRESS(adr+(hi*2+1+1)*8), tmp);
  124. SYSTEM.GET(ADDRESS(adr+(hi*2+1+1+1)*8), tmp);
  125. END;
  126. SYSTEM.PUT(ADDRESS(adr),numcritEntries);
  127. SYSTEM.PUT(ADDRESS(adr+8),memsize);
  128. TRACE(adr);
  129. RETURN EFI.Success;
  130. END GetMemoryMapping;
  131. (* find the size of the RAM by investigating the entries of the EFI Memory Map. *)
  132. PROCEDURE GetMemorySize*(VAR memsize : EFI.Int64 ) : EFI.Status;
  133. CONST
  134. approxMemMapSize = 2048; (* we actually can not resize the buffer. just hope its enough *)
  135. VAR
  136. MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
  137. status : EFI.Status;
  138. MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
  139. MemMapElement : EFI.MemoryDescriptorPointer;
  140. i, numEntries : EFI.Int;
  141. BEGIN
  142. MemMapSize := LEN(MemMap)*SIZEOF(EFI.MemoryDescriptor);
  143. status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
  144. IF status = EFI.ErrBufferTooSmall THEN
  145. (* we cant resize. We are doomed!*)
  146. RETURN status;
  147. END;
  148. numEntries := MemMapSize DIV DescriptorSize; (*DIV SIZEOF(EFI.MemoryDescriptor); *)
  149. memsize := 0;
  150. Trace.Ln();
  151. Trace.Address(MemMapSize);
  152. Trace.Ln();
  153. Trace.Address(SIZEOF(EFI.MemoryDescriptor));
  154. Trace.Ln();
  155. Trace.Address(36);
  156. Trace.Ln();
  157. Trace.Address(DescriptorSize);
  158. Trace.Ln();
  159. Trace.Address(DescriptorVersion);
  160. Trace.Ln();
  161. Trace.Ln();
  162. FOR i := 0 TO numEntries-1 DO
  163. MemMapElement := SYSTEM.VAL(EFI.MemoryDescriptorPointer, ADDRESSOF(MemMap[0])+i*DescriptorSize);
  164. (*
  165. MTLoaderCode* = 1;
  166. MTLoaderData* = 2;
  167. MTBootServicesCode* = 3;
  168. MTBootServicesData* = 4;
  169. MTRuntimeServicesCode* = 5;
  170. MTRuntimeServicesData* = 6;
  171. MTConventionalMemory*= 7;
  172. MTUnusableMemory* = 8;
  173. MTACPIReclaimMemorz* = 9;
  174. MTACPIMemoryNVSM* = 10;
  175. MTMemoryMappedIO* = 11;
  176. MTMemoryMappedIOPortSpace* = 12;
  177. MTPalCode* = 13;
  178. MTMaxMemoryType* = 14;
  179. *)
  180. (* IF (TRUE) THEN*)
  181. memsize := memsize + MemMapElement.NumberOfPages;
  182. (*IF (memsize < MemMap[i].PhysicalStart + MemMap[i].NumberOfPages*LONG(EFI.PageSize)) THEN
  183. memsize := MemMap[i].PhysicalStart + MemMap[i].NumberOfPages*LONG(EFI.PageSize);
  184. END;*)
  185. END;
  186. memsize := memsize * LONG(EFI.PageSize);
  187. Trace.Address(LONG(EFI.PageSize));
  188. Trace.Ln();
  189. Trace.Hex(memsize,8);
  190. Trace.Ln();
  191. (* memsize := SYSTEM.GET32(ADDRESSOF(memsize)+4); (* BUG! where ? *)*)
  192. RETURN EFI.Success;
  193. END GetMemorySize;
  194. (* stop bootservices. The idea is that we get the current memory map, s.t. the OS is aware of EFI allocated memory. We dont
  195. care so we just throw it away *)
  196. PROCEDURE ExitBootServices*(): EFI.Status;
  197. CONST
  198. approxMemMapSize = 2048; (* we actually can not resize the buffer. just hope its enough *)
  199. VAR
  200. MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
  201. status : EFI.Status;
  202. MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
  203. BEGIN
  204. MemMapSize := LEN(MemMap)*SIZEOF(EFI.MemoryDescriptor);
  205. REPEAT
  206. status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
  207. IF status = EFI.ErrBufferTooSmall THEN
  208. (* we cant resize. We are doomed! *)
  209. RETURN status;
  210. END;
  211. status := EFI.table.BS.ExitBootServices(EFI.imageHandle, MapKey);
  212. UNTIL status = EFI.Success;
  213. (*
  214. EFI.table.ConsoleInHandle := 0H;
  215. EFI.table.ConIn:= NIL;
  216. EFI.table.ConsoleOutHandle:= 0H;
  217. EFI.table.ConOut:= NIL;
  218. EFI.table.StandardErrorHandle:= 0H;
  219. EFI.table.StdErr:= NIL;
  220. EFI.table.BS:= NIL;*)
  221. RETURN EFI.Success;
  222. END ExitBootServices;
  223. (* Get the arguments given to the image *)
  224. PROCEDURE GetArgs*(VAR loadOptionsSize : LONGINT; VAR loadOptions : EFILoadedImage.PtrToArrayOfByte) : EFI.Status;
  225. VAR
  226. prot : EFI.Protocol; loadedImage : EFILoadedImage.Protocol;
  227. status : EFI.Status;
  228. BEGIN
  229. status := EFI.table.BS.HandleProtocol(EFI.imageHandle, EFILoadedImage.GUID, prot);
  230. IF status = EFI.Success THEN
  231. loadedImage := SYSTEM.VAL(EFILoadedImage.Protocol, prot);
  232. loadOptionsSize := loadedImage.LoadOptionsSize;
  233. loadOptions := loadedImage.LoadOptions;
  234. END;
  235. RETURN status;
  236. END GetArgs;
  237. (* (re-) initialize variables for GetNextArg. Automatically called by at the first call to GetNextArg. Can be used to reset GetNextArg.
  238. Assumes that EFI-Shell passes commandline as a string in the form "imagename (arguments)*" like e.g. unix shells do. *)
  239. PROCEDURE InitArgs*() : EFI.Status;
  240. VAR
  241. prot : EFI.Protocol; loadedImage : EFILoadedImage.Protocol;
  242. status : EFI.Status;
  243. loadOptionsSize : LONGINT;
  244. loadOptions : EFILoadedImage.PtrToArrayOfByte;
  245. BEGIN
  246. status := EFI.table.BS.HandleProtocol(EFI.imageHandle, EFILoadedImage.GUID, prot); (* not using GetArgs since we want access to other fields of the loadedImage-protocol *)
  247. IF status = EFI.Success THEN
  248. loadedImage := SYSTEM.VAL(EFILoadedImage.Protocol, prot);
  249. loadOptionsSize := loadedImage.LoadOptionsSize;
  250. loadOptions := loadedImage.LoadOptions;
  251. (* setup GetNextArg variables *)
  252. args:= SYSTEM.VAL(PtrToLongString, loadOptions);
  253. argLen := loadOptionsSize DIV 2; (* 16-bit characters *)
  254. argPos := 0;
  255. (* skip the 'imagename' by skipping the first word of the load options *)
  256. (* Do not skip if the image was not loaded directly by the firmware bootmanager.
  257. This should be useful to not have to type the name of the image as an argument when starting directly
  258. from the bootmanager while still being compatible to the EFI-Shell.
  259. ParentHandle should be NULL if the image was loaded by the firmware bootmanager. *)
  260. (* Apparently this does not work (at least it does not in qemu-EFI) although it should - therefore commented out
  261. IF (loadedImage.ParentHandle # 0) THEN *)
  262. WHILE (argPos < argLen) & (args[argPos] # 0) & (args[argPos] # ORD(' ')) DO
  263. INC(argPos);
  264. END;
  265. (*END; *)
  266. ELSE
  267. ReportError(status);
  268. END;
  269. RETURN status;
  270. END InitArgs;
  271. (* read one argument after another. Returns true iff successfully parsed.
  272. Treats ' ' (blank) as seperator between arguments. (text between '"' is NOT merged into one argument.
  273. *)
  274. PROCEDURE GetNextArg*(VAR arg : ARRAY OF EFI.Char16) : BOOLEAN;
  275. VAR
  276. status : EFI.Status;
  277. i : LONGINT;
  278. BEGIN
  279. IF args = NIL THEN
  280. status := InitArgs();
  281. IF (status # EFI.Success) THEN
  282. RETURN FALSE;
  283. END;
  284. END;
  285. (* skip whitspace *)
  286. WHILE (argPos < argLen) & (args[argPos] = ORD(' ')) DO INC(argPos); END;
  287. i := 0;
  288. WHILE (i < LEN(arg)) & (argPos < argLen) & (args[argPos] # 0) & (args[argPos] # ORD(' ')) DO
  289. arg[i] := args[argPos];
  290. INC(i); INC(argPos);
  291. END;
  292. RETURN (i > 0);
  293. END GetNextArg;
  294. (* read a string from simpleInputInterface *)
  295. PROCEDURE ReadString*(VAR buf : ARRAY OF EFI.Char16);
  296. CONST ScanCodeNull = 0; (* if ScanCode = 0 then UnicodeChar is valid. Else a special key was hit (e.g ESC, Fx,..) *)
  297. CharLF = 0AH;
  298. CharCR = 0DH;
  299. VAR key : EFI.InputKey; i : LONGINT;
  300. status : EFI.Status;
  301. ConIn : POINTER TO EFI.SimpleInputInterface;
  302. ConOut : POINTER TO EFI.SimpleTextOutputInterface;
  303. newline, cursorEnabled : BOOLEAN;
  304. lastChar : ARRAY 2 OF EFI.Char16;
  305. BEGIN
  306. ConIn := EFI.table.ConIn;
  307. ConOut := EFI.table.ConOut;
  308. lastChar[1] := 0;
  309. cursorEnabled := ConOut.Mode.CursorVisible;
  310. IF (~cursorEnabled) THEN
  311. status := ConOut.EnableCursor(ConOut, TRUE);
  312. END;
  313. status := ConIn.Reset(ConIn, FALSE);
  314. newline := FALSE; i := 0;
  315. WHILE (i < LEN(buf)-1) & (~newline) DO
  316. status := ConIn.ReadKey(ConIn, key);
  317. IF (status = EFI.Success) & (key.ScanCode = ScanCodeNull) THEN
  318. IF (key.UnicodeChar # CharLF) & (key.UnicodeChar # CharCR) THEN
  319. buf[i] := key.UnicodeChar;
  320. lastChar[0] := key.UnicodeChar;
  321. ELSE
  322. buf[i] := 0H;
  323. newline := TRUE;
  324. lastChar[0] := key.UnicodeChar;
  325. END;
  326. status := ConOut.OutputString(ConOut, lastChar);
  327. INC(i);
  328. END;
  329. END;
  330. buf[LEN(buf)-1] := 0H;
  331. IF (~cursorEnabled) THEN
  332. status := ConOut.EnableCursor(ConOut, FALSE);
  333. END;
  334. END ReadString;
  335. (* convert signed integer to a string *)
  336. PROCEDURE IntToString* (CONST x : LONGINT; VAR s : ARRAY OF CHAR);
  337. VAR i, x0, slen, start : LONGINT;
  338. BEGIN
  339. IF x = MIN (LONGINT) THEN
  340. s := "-2147483648";
  341. RETURN;
  342. END;
  343. slen := LEN(s)-1;
  344. IF (slen > 11) THEN
  345. slen := 11;
  346. END;
  347. s[slen] := 0X;
  348. start := 0;
  349. IF (x < 0) & ( slen > 0 ) THEN
  350. x0 := -x;
  351. s[0] := '-'; start := 1;
  352. END;
  353. i := slen;
  354. WHILE ( i > start ) DO
  355. DEC(i);
  356. s[i] := CHR (x0 MOD 10 + 30H);
  357. x0 := x0 DIV 10;
  358. END;
  359. END IntToString;
  360. (* Copied from BIOS.I386.Machine.Mod - StrToInt *)
  361. (** Convert a string to an integer. Parameter i specifies where in the string scanning should begin (usually 0 in the first call). Scanning stops at the first non-valid character, and i returns the updated position. Parameter s is the string to be scanned. The value is returned as result, or 0 if not valid. Syntax: number = ["-"] digit {digit} ["H" | "h"] . digit = "0" | ... "9" | "A" .. "F" | "a" .. "f" . If the number contains any hexdecimal letter, or if it ends in "H" or "h", it is interpreted as hexadecimal. *)
  362. PROCEDURE StringToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  363. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  364. BEGIN
  365. vd := 0; vh := 0; hex := FALSE;
  366. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  367. LOOP
  368. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  369. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  370. ELSE EXIT
  371. END;
  372. vd := 10*vd + d; vh := 16*vh + d;
  373. INC (i)
  374. END;
  375. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  376. IF hex THEN vd := vh END;
  377. RETURN sgn * vd
  378. END StringToInt;
  379. (* copy the String 'str' to the char16-String 'lstr'. If 'lstr' is shorter than 'str' the prefix fitting into 'lstr' is copied. *)
  380. PROCEDURE StringToLongString*(CONST str : ARRAY OF CHAR; VAR lstr : ARRAY OF EFI.Char16);
  381. VAR strlen, lstrlen,i : LONGINT;
  382. BEGIN
  383. strlen := LEN(str);
  384. lstrlen := LEN(lstr);
  385. i := 0;
  386. WHILE (i < strlen) & (i < lstrlen) & (ORD(str[i]) # 0) DO
  387. lstr[i] := ORD(str[i]);
  388. INC(i);
  389. END;
  390. IF lstrlen > 0 THEN
  391. lstr[i] := 0;
  392. END;
  393. END StringToLongString;
  394. (* returns the protocol identified by 'guid'. If there are multiple handles that handle this protocol, one is chosen arbitrarily *)
  395. PROCEDURE GetProtocol*(CONST guid : EFI.GUID; VAR prot : EFI.Protocol) : EFI.Status;
  396. VAR
  397. handle : EFI.Handle;
  398. handleBuf : ARRAY 512 OF EFI.Handle; (* make it large enough, we cant resize easily *)
  399. handleBufSize, i : EFI.Int;
  400. status : EFI.Status;
  401. BEGIN
  402. handleBufSize := LEN(handleBuf) * SIZEOF(EFI.Handle);
  403. status := EFI.table.BS.LocateHandle(EFI.ByProtocol, guid, 0, handleBufSize, handleBuf);
  404. IF (status = EFI.Success) & (handleBufSize > 0) THEN
  405. i := handleBufSize DIV SIZEOF(EFI.Handle);
  406. WHILE(i>0) DO
  407. DEC(i);
  408. handle := handleBuf[i];
  409. status := EFI.table.BS.HandleProtocol(handle, guid, prot);
  410. IF status = EFI.Success THEN RETURN EFI.Success; END;
  411. END;
  412. RETURN EFI.Error;
  413. END;
  414. RETURN status;
  415. END GetProtocol;
  416. PROCEDURE GetFileSize*(file : EFIFileProtocol.Protocol) : EFI.Int64;
  417. VAR
  418. status : EFI.Status;
  419. infoBuf : EFIFileProtocol.FileInfo;
  420. infoBufSize : EFI.Int;
  421. fileSize : EFI.Int64;
  422. BEGIN
  423. infoBufSize := SIZEOF(EFIFileProtocol.FileInfo);
  424. status := file.GetInfo(file, EFIFileProtocol.FileInfoGUID, infoBufSize, infoBuf);
  425. IF (status = EFI.Success) THEN
  426. fileSize := infoBuf.FileSize;
  427. END;
  428. RETURN fileSize;
  429. END GetFileSize;
  430. (* search 'fn' on all devices that handle the SimpleFS protocol (= FAT partitions) and open it read-write *)
  431. PROCEDURE OpenFile*(CONST fn : ARRAY OF EFI.Char16) : EFIFileProtocol.Protocol;
  432. VAR
  433. status : EFI.Status;
  434. handleBuf : ARRAY 128 OF EFI.Handle; (* make it large enough, we cant resize easily *)
  435. handleBufSize : EFI.Int;
  436. file : EFIFileProtocol.Protocol;
  437. done : BOOLEAN;
  438. iter : LONGINT;
  439. BEGIN
  440. (* get all devices (or device drivers, handlers or what ever) that support the EFISimpleFS *)
  441. handleBufSize := LEN(handleBuf) * SIZEOF(EFI.Handle);
  442. status := EFI.table.BS.LocateHandle(EFI.ByProtocol, EFISimpleFS.GUID, 0, handleBufSize, handleBuf);
  443. IF (status = EFI.Success) & (handleBufSize > 0) THEN
  444. done := FALSE;
  445. iter := 0;
  446. (* look for the file on each device *)
  447. WHILE (iter < handleBufSize DIV SIZEOF(EFI.Handle)) & (~done) DO
  448. file := OpenFileOnDevice(fn, handleBuf[iter]);
  449. IF (file # NIL) THEN
  450. done := TRUE;
  451. END;
  452. INC(iter);
  453. END;
  454. ELSE
  455. file := NIL;
  456. END;
  457. RETURN file;
  458. END OpenFile;
  459. (* look for file 'fn' on device 'deviceHandle' and try to open it read-write. Returns NIL if not found *)
  460. PROCEDURE OpenFileOnDevice(CONST fn : ARRAY OF EFI.Char16; deviceHandle : EFI.Handle) : EFIFileProtocol.Protocol;
  461. VAR
  462. root : EFIFileProtocol.Protocol;
  463. file : EFIFileProtocol.Protocol;
  464. protSimpleFS : EFISimpleFS.Protocol;
  465. prot : EFI.Protocol;
  466. status : EFI.Status;
  467. BEGIN
  468. file := NIL;
  469. (* first get a SimpleFS-Protocol for handle *)
  470. status := EFI.table.BS.HandleProtocol(deviceHandle, EFISimpleFS.GUID, prot);
  471. protSimpleFS := SYSTEM.VAL(EFISimpleFS.Protocol,prot);
  472. IF (status = EFI.Success) & (protSimpleFS # NIL) THEN
  473. (* get a File-descriptor thingy for the root directory *)
  474. status := protSimpleFS.OpenVolume(protSimpleFS, root);
  475. IF (status = EFI.Success) THEN
  476. status := root.Open(root, file, fn, EFIFileProtocol.ModeRead, 0);
  477. IF (status # EFI.Success) THEN
  478. file := NIL;
  479. END;
  480. END;
  481. END;
  482. RETURN file;
  483. END OpenFileOnDevice;
  484. (* allocate memory and copy the content of the file to memory. If loadAddr = -1 an arbitrary memory page will be allocated *)
  485. PROCEDURE LoadFile*(file : EFIFileProtocol.Protocol; VAR loadAddr : ADDRESS) : EFI.Status;
  486. VAR
  487. status : EFI.Status;
  488. fileSize : EFI.Int64;
  489. numPages : EFI.Int;
  490. addr : EFI.PhysicalAddress;
  491. memSize : EFI.Int;
  492. BEGIN
  493. fileSize := GetFileSize(file);
  494. numPages := SHORT(fileSize DIV EFI.PageSize) + 1;
  495. addr := loadAddr;
  496. status := AllocateMemory(addr, numPages);
  497. (* now addr contains the base address of the allocated pages *)
  498. IF status = EFI.Success THEN
  499. loadAddr := SYSTEM.VAL(ADDRESS, addr);
  500. memSize := SYSTEM.VAL(EFI.Int, fileSize);
  501. status := file.Read(file, memSize, loadAddr);
  502. END;
  503. RETURN status;
  504. END LoadFile;
  505. (* Reports a description of the error code *)
  506. PROCEDURE ReportError*(status : EFI.Status);
  507. BEGIN
  508. (*
  509. CASE status OF
  510. |EFI.Success : Trace.String("Success");
  511. (* Warnings *)
  512. | EFI.WarnUnknownGlyph : Trace.String("Warning : Unknown Glyph");
  513. | EFI.WarnDeleteFailure : Trace.String("Warning : Delete Failure");
  514. | EFI.WarnWriteFailure : Trace.String("Warning : Write Failure");
  515. | EFI.WarnBufferTooSmall : Trace.String("Warning : Buffer Too Small");
  516. (* Errors*)
  517. | EFI.ErrLoadError : Trace.String("Error : Load Error");
  518. | EFI.ErrInvalidParameter : Trace.String("Error : Invalid Parameter");
  519. | EFI.ErrUnsupported : Trace.String("Error : Unsupported");
  520. | EFI.ErrBadBufferSize : Trace.String("Error : Bad Buffer Size");
  521. | EFI.ErrBufferTooSmall : Trace.String("Error : Buffer Too Small");
  522. (* ... TODO ... *)
  523. | EFI.ErrNotFound : Trace.String("Error : Not Found");
  524. (* ... TODO ... *)
  525. | EFI.ErrEndOfFile : Trace.String("Error : End Of File");
  526. | EFI.ErrInvalidLanguage : Trace.String("Error : Invalid Language");
  527. END;
  528. *)
  529. Trace.String("Error Code: "); Trace.Int(LONGINT(status - EFI.Error), 0);
  530. Trace.Ln;
  531. END ReportError;
  532. BEGIN
  533. numAllocations := 0;
  534. args := NIL;
  535. END EFILib.