EFIA2Loader.Mod 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. MODULE EFIA2Loader; (** AUTHOR "Matthias Frei"; PURPOSE "EFI A2 Boot Loader"; *)
  2. IMPORT
  3. SYSTEM, EFI, Machine := EFIMachine, EFILib, EFIFileProtocol, EFIGraphicsOutput, EFIGraphicalConsole, Trace;
  4. CONST
  5. traceDebug = TRUE;
  6. (* address to which the executable will be loaded to. Loaded to arbitrary address if = -1 *)
  7. kernelAddress = 100000H;
  8. (* address at which the boot table is generated. Arbitrary if -1 *)
  9. bootTableAddress = -1;
  10. VAR
  11. bootTableBegin : ADDRESS; (* address at which boot table is really located. Can be equal to bootTableAddress *)
  12. bootTableEnd : ADDRESS; (* bootTableBegin + current size of bootTable - sizeof sentinel (=5) + 1. *)
  13. bootTableCfgStrEntry : ADDRESS; (* address of the config string entry (type 8) of the boot table *)
  14. (* search a mode that with the preferred horizontal and vertical resolution. Returns the corresponding mode
  15. number or -1 if no such mode is found or if an error occurs *)
  16. PROCEDURE SearchGraphicsMode(prot : EFIGraphicsOutput.Protocol; prefWidth, prefHeight, prefDepth, prefFormat : LONGINT; VAR info: EFIGraphicsOutput.GraphicsModeInfo): LONGINT;
  17. VAR
  18. mode : EFIGraphicsOutput.GraphicsMode;
  19. sizeofInfo : EFI.Int;
  20. maxMode : EFI.Int32;
  21. i : LONGINT;
  22. status : EFI.Status;
  23. BEGIN
  24. (* the currently set mode stores the number of available modes. Valid mode numbers are 0 to maxMode-1 *)
  25. mode := prot.Mode;
  26. maxMode := mode.MaxMode;
  27. (* enumerate all modes *)
  28. FOR i := 0 TO maxMode-1 DO
  29. (* get info about mode i *)
  30. status := prot.QueryMode(prot, i, sizeofInfo, info); (* ignore sizeofInfo. Just some compatibility stuff *)
  31. IF (status # EFI.Success) THEN
  32. RETURN -1;
  33. END;
  34. (* now check whether this is the mode we are looking for *)
  35. (* IF (prefWidth = info.HorizontalResolution) & (prefHeight = info.VerticalResolution)
  36. & (prefFormat = info.PixelFormat) & (prefDepth = 32) THEN (* all pixel formats are 32 bit *) *)
  37. IF (prefWidth = info.HorizontalResolution) & (prefHeight = info.VerticalResolution)
  38. & (prefDepth = 32) THEN (* all pixel formats are 32 bit *)
  39. RETURN i;
  40. END;
  41. END;
  42. RETURN -1;
  43. END SearchGraphicsMode;
  44. PROCEDURE GetFrameBuffer(prefWidth, prefHeight, prefDepth, prefFormat : LONGINT; VAR framebufAddr : ADDRESS; VAR framebufSize : SIZE; VAR info: EFIGraphicsOutput.GraphicsModeInfo): EFI.Status;
  45. VAR
  46. handle : EFI.Handle;
  47. handleBuf : ARRAY 128 OF EFI.Handle;
  48. handleBufSize, i : EFI.Int;
  49. prot : EFI.Protocol; goProt : EFIGraphicsOutput.Protocol;
  50. modeNumber : LONGINT;
  51. framebufPhysAddr : EFI.PhysicalAddress;
  52. status : EFI.Status;
  53. BEGIN
  54. handleBufSize := LEN(handleBuf)*SIZEOF(EFI.Handle);
  55. status := EFI.table.BS.LocateHandle(EFI.ByProtocol, EFIGraphicsOutput.GUID, 0, handleBufSize, handleBuf);
  56. IF status = EFI.Success THEN
  57. i := handleBufSize DIV SIZEOF(EFI.Handle); (* probably either 0 or 1. *)
  58. WHILE i > 0 DO
  59. DEC(i);
  60. handle := handleBuf[i];
  61. status := EFI.table.BS.HandleProtocol(handle, EFIGraphicsOutput.GUID, prot);
  62. goProt := SYSTEM.VAL(EFIGraphicsOutput.Protocol, prot);
  63. IF status = EFI.Success THEN
  64. modeNumber := SearchGraphicsMode(goProt, prefWidth, prefHeight, prefDepth, prefFormat, info);
  65. IF modeNumber >= 0 THEN
  66. status := goProt.SetMode(goProt, modeNumber);
  67. IF (status = EFI.Success) & (goProt.Mode.Mode = modeNumber) THEN
  68. framebufPhysAddr := goProt.Mode.FrameBufferBase;
  69. framebufAddr := SYSTEM.VAL(ADDRESS, framebufPhysAddr);
  70. framebufSize := goProt.Mode.FrameBufferSize;
  71. RETURN EFI.Success;
  72. END;
  73. END;
  74. END;
  75. END;
  76. END;
  77. RETURN EFI.Error;
  78. END GetFrameBuffer;
  79. (* Prints all available graphics modes where PixelFormat # BltOnly *)
  80. PROCEDURE PrintGraphicsModes;
  81. VAR
  82. handle : EFI.Handle;
  83. handleBuf : ARRAY 512 OF EFI.Handle;
  84. handleBufSize, i: EFI.Int; j : LONGINT;
  85. prot : EFI.Protocol; goProt : EFIGraphicsOutput.Protocol;
  86. mode : EFIGraphicsOutput.GraphicsMode;
  87. info : EFIGraphicsOutput.GraphicsModeInfo;
  88. sizeofInfo : EFI.Int;
  89. maxMode : EFI.Int32;
  90. status : EFI.Status;
  91. BEGIN
  92. handleBufSize := LEN(handleBuf)*SIZEOF(EFI.Handle);
  93. status := EFI.table.BS.LocateHandle(EFI.ByProtocol, EFIGraphicsOutput.GUID, 0, handleBufSize, handleBuf);
  94. IF status = EFI.Success THEN
  95. i := handleBufSize DIV SIZEOF(EFI.Handle); (* probably either 0 or 1. *)
  96. IF (i = 0) THEN
  97. Trace.String(" - none - "); Trace.Ln;
  98. END;
  99. WHILE i > 0 DO
  100. DEC(i);
  101. handle := handleBuf[i];
  102. status := EFI.table.BS.HandleProtocol(handle, EFIGraphicsOutput.GUID, prot);
  103. goProt := SYSTEM.VAL(EFIGraphicsOutput.Protocol, prot);
  104. IF status = EFI.Success THEN
  105. (* the currently set mode stores the number of available modes. Valid mode numbers are 0 to maxMode-1 *)
  106. mode := goProt.Mode;
  107. maxMode := mode.MaxMode;
  108. (* enumerate all modes *)
  109. FOR j := 0 TO maxMode-1 DO
  110. (* get info about mode j *)
  111. status := goProt.QueryMode(goProt, j, sizeofInfo, info); (* ignore sizeofInfo. Just some compatibility stuff *)
  112. IF (status # EFI.Success) THEN
  113. RETURN;
  114. END;
  115. Trace.Int(info.HorizontalResolution, 0); Trace.String("x");
  116. Trace.Int(info.VerticalResolution, 0); Trace.String("x");
  117. Trace.Int(32, 0); Trace.String(" - ");
  118. CASE info.PixelFormat OF
  119. EFIGraphicsOutput.PFRGBX8Bit : Trace.String("RGB");
  120. | EFIGraphicsOutput.PFBGRX8Bit : Trace.String("BGR");
  121. | EFIGraphicsOutput.PFBitMask : Trace.String("R: "); Trace.Hex(info.PixelBitmask.RedMask,8);
  122. Trace.String("G: "); Trace.Hex(info.PixelBitmask.GreenMask,8);
  123. Trace.String("B: "); Trace.Hex(info.PixelBitmask.BlueMask,8);
  124. | EFIGraphicsOutput.PFBltOnly : Trace.String("Blocktransfer only - no physical framebuffer");
  125. END;
  126. Trace.Ln;
  127. END;
  128. END;
  129. END;
  130. ELSE
  131. Trace.String("Error while accessing GraphicsOutputProtocol.");Trace.Ln;
  132. EFILib.ReportError(status);
  133. END;
  134. END PrintGraphicsModes;
  135. (* Loads the configuration file and creates the corresponding boot-table. *)
  136. PROCEDURE LoadBootTable(CONST configFileName : ARRAY OF EFI.Char16; VAR btAddr : ADDRESS) : EFI.Status;
  137. VAR
  138. configFile : EFIFileProtocol.Protocol;
  139. cfAddr, cfPos, cfEnd : ADDRESS;
  140. btAddrPhys : EFI.PhysicalAddress;
  141. btPos : ADDRESS;
  142. status : EFI.Status;
  143. type : LONGINT;
  144. fileSize : LONGINT;
  145. cfgname, cfgval : ADDRESS;
  146. cfgnamelen, cfgvallen : LONGINT;
  147. parseError : BOOLEAN;
  148. ramSize : EFI.Int64;
  149. PROCEDURE ReportError(at : ADDRESS);
  150. VAR status : EFI.Status;
  151. BEGIN
  152. parseError := TRUE;
  153. Trace.String("Sytnax error in file ");
  154. status := EFI.table.ConOut.OutputString(EFI.table.ConOut, configFileName); (* configFileName is a Unicode string *)
  155. Trace.String(" at position ");
  156. Trace.Address(at);
  157. Trace.Ln;
  158. END ReportError;
  159. PROCEDURE IsWhitespace(ch : CHAR) : BOOLEAN;
  160. BEGIN
  161. RETURN (ch = ' ') OR (ch = 09X) OR (ch = 0AX); (* space, tab or newline *)
  162. END IsWhitespace;
  163. (* searches the next configuration entry in the config file and returns the positions and lengths of its name and value *)
  164. PROCEDURE ReadConfig (VAR name : ADDRESS; VAR namelen : LONGINT; VAR val : ADDRESS; VAR vallen : LONGINT) : BOOLEAN;
  165. VAR ch : CHAR;
  166. BEGIN
  167. (* skip whitespace *)
  168. IF (cfPos # cfEnd) THEN SYSTEM.GET(cfPos, ch); INC(cfPos); END;
  169. WHILE (cfPos # cfEnd) & IsWhitespace(ch) DO
  170. SYSTEM.GET(cfPos, ch); INC(cfPos);
  171. END;
  172. IF (ch = '~') THEN RETURN FALSE; END;
  173. name := cfPos-1;
  174. namelen := 0;
  175. (* skip name *)
  176. WHILE (cfPos # cfEnd) & (ch # '=') & ~IsWhitespace(ch) DO
  177. INC(namelen);
  178. SYSTEM.GET(cfPos, ch); INC(cfPos);
  179. END;
  180. (* skip whitespace before = *)
  181. WHILE (cfPos # cfEnd) & IsWhitespace(ch) DO
  182. SYSTEM.GET(cfPos, ch); INC(cfPos);
  183. END;
  184. IF (ch # '=') THEN ReportError(cfPos - cfAddr); RETURN FALSE; END;
  185. IF (cfPos # cfEnd) THEN SYSTEM.GET(cfPos, ch); INC(cfPos); END;
  186. (* skip whitespace after = *)
  187. WHILE (cfPos # cfEnd) & IsWhitespace(ch) DO
  188. SYSTEM.GET(cfPos, ch); INC(cfPos);
  189. END;
  190. IF (ch # '"') THEN ReportError(cfPos - cfAddr); RETURN FALSE; END;
  191. IF (cfPos # cfEnd) THEN SYSTEM.GET(cfPos, ch); INC(cfPos); END;
  192. val := cfPos-1;
  193. vallen := 0;
  194. (* skip val *)
  195. WHILE (cfPos # cfEnd) & (ch # '"') DO
  196. INC(vallen);
  197. SYSTEM.GET(cfPos, ch); INC(cfPos);
  198. END;
  199. IF (ch # '"') THEN ReportError(cfPos - cfAddr); RETURN FALSE; END;
  200. IF (name = cfEnd) OR (val = cfEnd) THEN
  201. RETURN FALSE;
  202. END;
  203. RETURN TRUE;
  204. END ReadConfig;
  205. BEGIN
  206. (* open and load the configuration file *)
  207. configFile := EFILib.OpenFile(configFileName);
  208. IF (configFile = NIL) THEN
  209. Trace.String("Error: Could not find file ");
  210. status := EFI.table.ConOut.OutputString(EFI.table.ConOut, configFileName);
  211. Trace.Ln;
  212. RETURN EFI.ErrNotFound;
  213. END;
  214. cfAddr := -1; (* don't care *)
  215. status := EFILib.LoadFile(configFile, cfAddr);
  216. IF (status # EFI.Success) THEN
  217. RETURN status;
  218. END;
  219. fileSize := SHORT(EFILib.GetFileSize(configFile));
  220. cfPos := cfAddr;
  221. cfEnd := cfAddr + fileSize;
  222. (* allocate memory for the boot table *)
  223. btAddrPhys := bootTableAddress;
  224. status := EFILib.AllocateMemory(btAddrPhys, SHORT(fileSize DIV EFI.PageSize) + 3); (* a few additional pages *)
  225. (* now bootTablePhAddr contains the base address of the allocated pages *)
  226. IF status # EFI.Success THEN
  227. RETURN status;
  228. END;
  229. bootTableBegin := SYSTEM.VAL(ADDRESS,btAddrPhys);
  230. btAddr := bootTableBegin; (* out *)
  231. btPos := bootTableBegin;
  232. (* boot memory/top of low memory. Trying to stay compatible with OBL.Asm *)
  233. type := 3;
  234. SYSTEM.PUT32(btPos, type); INC(btPos, 4);
  235. SYSTEM.PUT32(btPos, 16); INC(btPos, 4); (* entry size *)
  236. SYSTEM.PUT32(btPos, 0); INC(btPos, 4); (* boot memory address (?) *)
  237. SYSTEM.PUT32(btPos, 640*1024); INC(btPos, 4); (* boot memory size (in bytes) *)
  238. (* free memory/extended memory size *)
  239. status := EFILib.GetMemorySize(ramSize);
  240. type := 4;
  241. SYSTEM.PUT32(btPos, type); INC(btPos, 4);
  242. SYSTEM.PUT32(btPos, 16); INC(btPos, 4); (* entry size *)
  243. SYSTEM.PUT32(btPos, 100000H); INC(btPos, 4); (* extended memory address *)
  244. SYSTEM.PUT32(btPos, SHORT(ramSize) - 100000H); INC(btPos, 4); (* extended memory size *)
  245. IF traceDebug THEN
  246. Trace.String("DEBUG: ramsize: "); Trace.Hex(SHORT(ramSize), 0); Trace.String("H B"); Trace.Ln;
  247. END;
  248. (* config strings; Parse the configuration file and copy the content to the boot table *)
  249. type := 8;
  250. (* write a config string entry 'header'. *)
  251. bootTableCfgStrEntry := btPos;
  252. SYSTEM.PUT32(btPos, type); INC(btPos, 4);
  253. SYSTEM.PUT32(btPos, 0); INC(btPos, 4); (* reserve space for the size field *)
  254. bootTableEnd := btPos;
  255. (* write trailer - will be overwritten by addconfig *)
  256. SYSTEM.PUT8(btPos, 0); INC(btPos);
  257. SYSTEM.PUT32(btPos, -1); INC(btPos, 4);
  258. parseError := FALSE;
  259. WHILE (ReadConfig(cfgname, cfgnamelen, cfgval, cfgvallen)) DO
  260. AddConfigA(cfgname, cfgnamelen, cfgval, cfgvallen);
  261. END;
  262. IF (parseError) THEN
  263. RETURN EFI.Error;
  264. ELSE
  265. RETURN EFI.Success;
  266. END;
  267. END LoadBootTable;
  268. PROCEDURE AddConfig(CONST name, val : ARRAY OF CHAR);
  269. VAR strlenName, strlenVal : LONGINT;
  270. BEGIN
  271. strlenName:=0; WHILE (name[strlenName] # 0X) & (strlenName < LEN(name)) DO INC(strlenName); END;
  272. strlenVal:=0; WHILE (val[strlenVal] # 0X) & (strlenVal < LEN(val)) DO INC(strlenVal); END;
  273. AddConfigA(ADDRESSOF(name[0]), strlenName, ADDRESSOF(val[0]), strlenVal);
  274. END AddConfig;
  275. (* add a config string entry to the boot table. The table always ends with a termination symbol which is overwritten
  276. if another entry is added. The lengths must not include a terminating 0. *)
  277. PROCEDURE AddConfigA(name : ADDRESS; namelen : LONGINT; val : ADDRESS; vallen : LONGINT);
  278. VAR btEnd : ADDRESS;
  279. cfgStrSize : SIZE;
  280. BEGIN
  281. btEnd := bootTableEnd;
  282. SYSTEM.MOVE(name,btEnd,namelen);
  283. INC(btEnd,namelen);
  284. SYSTEM.PUT(btEnd, 0); INC(btEnd); (*separator *)
  285. SYSTEM.MOVE(val,btEnd,vallen);
  286. INC(btEnd,vallen);
  287. SYSTEM.PUT(btEnd, 0); INC(btEnd); (*separator *)
  288. INC(bootTableEnd, namelen + 1 + vallen + 1);
  289. SYSTEM.PUT(btEnd, 0); INC(btEnd); (* marks the end of the config string entry *)
  290. SYSTEM.PUT32(btEnd, -1); (* marks the end of the table *)
  291. (* do not increment bootTableEnd here again. the 0 and the -1 will be overwritten if another entry is added *)
  292. cfgStrSize := bootTableEnd + 1 - bootTableCfgStrEntry; (* size including the 0 byte of the trailer *)
  293. SYSTEM.PUT32(bootTableCfgStrEntry + 4, cfgStrSize);
  294. END AddConfigA;
  295. (* search in the config string entries of the boot table (NOT in the config file) for the configuration with name 'name' *)
  296. PROCEDURE GetConfig(CONST name : ARRAY OF CHAR; VAR val : ARRAY OF CHAR);
  297. VAR btIdx : ADDRESS; i : LONGINT; ch : CHAR;
  298. BEGIN
  299. btIdx := bootTableCfgStrEntry + 8; (* skip type and size fields *)
  300. (* copied from I386.Machine.Mod - GetConfig *)
  301. LOOP
  302. SYSTEM.GET(btIdx,ch);
  303. IF ch = 0X THEN EXIT END;
  304. i := 0;
  305. LOOP
  306. SYSTEM.GET(btIdx,ch);
  307. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  308. INC (i); INC (btIdx)
  309. END;
  310. IF (ch = 0X) & (name[i] = 0X) THEN (* found: (src^ = 0X) & (name[i] = 0X) *)
  311. i := 0;
  312. REPEAT
  313. INC (btIdx); SYSTEM.GET(btIdx,ch); val[i] := ch; INC (i);
  314. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  315. UNTIL ch = 0X;
  316. val[i] := 0X; RETURN
  317. ELSE
  318. WHILE ch # 0X DO (* skip to end of name *)
  319. INC (btIdx); SYSTEM.GET(btIdx,ch);
  320. END;
  321. INC (btIdx);
  322. REPEAT (* skip to end of value *)
  323. SYSTEM.GET(btIdx,ch); INC (btIdx)
  324. UNTIL ch = 0X
  325. END
  326. END;
  327. val[0] := 0X
  328. END GetConfig;
  329. PROCEDURE Allocate(allocAddr: EFI.PhysicalAddress; kernelPages: LONGINT): EFI.Status;
  330. VAR allocAdrCopy : EFI.PhysicalAddress; chunkPages: LONGINT; status: EFI.Status;
  331. BEGIN
  332. chunkPages := kernelPages;
  333. chunkPages := 1;
  334. REPEAT
  335. allocAdrCopy := allocAddr; (* to protect allocAddr from being overwritten in AllocateMemory *)
  336. status := EFILib.AllocateMemory(allocAdrCopy, chunkPages);
  337. IF status = EFI.Success THEN
  338. DEC(kernelPages, chunkPages);
  339. allocAddr := allocAddr + EFI.PageSize*chunkPages;
  340. ELSE
  341. TRACE(kernelPages, chunkPages, allocAddr, status);
  342. chunkPages := chunkPages DIV 2;
  343. IF chunkPages > kernelPages THEN chunkPages := kernelPages END;
  344. END;
  345. UNTIL (kernelPages = 0) OR (chunkPages = 0);
  346. RETURN status;
  347. END Allocate;
  348. (* loads the kernel image to kernelAddress if possible. Otherwise loads it to somewhere else and return WarnWriteFailure.
  349. Allocates makes sure the memory at kernelRelocAddress is allocated (by us or by someone else) s.t.
  350. the boot table will certainly not be allocated there.
  351. *)
  352. PROCEDURE LoadKernel(CONST kernelFileName : ARRAY OF EFI.Char16; VAR kernelAddr: ADDRESS; VAR kernelSize : LONGINT) : EFI.Status;
  353. VAR
  354. loadAddr : ADDRESS;
  355. allocAddr : EFI.PhysicalAddress;
  356. kernelImageFile : EFIFileProtocol.Protocol;
  357. kernelPages : LONGINT;
  358. i : LONGINT;
  359. status : EFI.Status;
  360. BEGIN
  361. kernelImageFile := EFILib.OpenFile(kernelFileName);
  362. IF (kernelImageFile # NIL) THEN
  363. kernelSize := SHORT(EFILib.GetFileSize(kernelImageFile));
  364. TRACE(kernelSize);
  365. kernelPages := (kernelSize DIV EFI.PageSize) + 1;
  366. (* allocate all memory at kernelRelocAddress *)
  367. IF (kernelAddress # -1) THEN
  368. (*status := Allocate(kernelRelocAddress, kernelPages);*)
  369. TRACE(status);
  370. (*
  371. allocAddr := kernelRelocAddress;
  372. status := EFILib.AllocateMemory(allocAddr, kernelPages);
  373. TRACE(status);
  374. (* try to make sure all pages are allocated somehow *)
  375. IF (status # EFI.Success) THEN
  376. FOR i := 0 TO kernelPages DO
  377. status := EFI.Success;
  378. status := EFILib.AllocateMemory(allocAddr, 1);
  379. TRACE(status, allocAddr);
  380. allocAddr := allocAddr + EFI.PageSize;
  381. END;
  382. END;
  383. *)
  384. END;
  385. loadAddr := kernelAddress;
  386. (*loadAddr := 400000H; *)
  387. allocAddr:= 0; (*we use the variable to reserve page 0 and 1 *)
  388. status := EFILib.AllocateMemory(allocAddr, 2); (* allocate page 0 and 1 to be sure the kernel is not put there *)
  389. IF status # EFI.Success THEN
  390. Trace.String("could not allocate page 0 and 1 - this might be a problem for the relocation process");
  391. END;
  392. (*
  393. loadAddr := -1; (*we let EFI decide where to put it *)
  394. *)
  395. status := EFILib.LoadFile(kernelImageFile, loadAddr);
  396. IF (status = EFI.Success ) THEN
  397. TRACE(loadAddr);
  398. kernelAddr := loadAddr;
  399. TRACE(kernelAddress);
  400. RETURN EFI.Success;
  401. ELSE
  402. TRACE("could not load kernel with fixed adr");
  403. (* try to recover: load it anywhere and relocate it later. make sure all pages at kernelAddress are allocated *)
  404. (*status := Allocate(kernelAddress, kernelPages);*)
  405. TRACE(status);
  406. (*
  407. allocAddr := kernelAddress;
  408. FOR i := 0 TO kernelPages DO
  409. status := EFI.Success;
  410. status := EFILib.AllocateMemory(allocAddr, 1);
  411. TRACE(status, allocAddr);
  412. allocAddr := allocAddr + EFI.PageSize;
  413. END;
  414. *)
  415. loadAddr := -1;
  416. status := EFILib.LoadFile(kernelImageFile, loadAddr);
  417. TRACE(status);
  418. IF (status = EFI.Success) THEN
  419. TRACE("loaded kernel to ", loadAddr);
  420. kernelAddr := loadAddr;
  421. TRACE(kernelAddress);
  422. RETURN EFI.WarnWriteFailure;
  423. ELSE
  424. RETURN EFI.Error;
  425. END;
  426. END;
  427. ELSE
  428. Trace.String("Error: Could not find file ");
  429. status := EFI.table.ConOut.OutputString(EFI.table.ConOut, kernelFileName);
  430. Trace.Ln;
  431. RETURN EFI.ErrNotFound;
  432. END;
  433. END LoadKernel;
  434. PROCEDURE LoadA2;
  435. VAR
  436. kernelAddr, btAddr, fbAddr, highAddr, memmapAddr: ADDRESS;
  437. fbSize: EFI.Int;
  438. adr: EFI.PhysicalAddress;
  439. kernelSize: LONGINT;
  440. kernelStat, btStat, fbStat, status, memmapStat : EFI.Status;
  441. kernelFileName, configFileName, arg : ARRAY 128 OF EFI.Char16;
  442. val : ARRAY 100 OF CHAR;
  443. i, dWidth, dHeight, dDepth, dFormat : LONGINT;
  444. size: EFI.Int64;
  445. buf : ARRAY 100 OF EFI.Char16;
  446. fbInfo: EFIGraphicsOutput.GraphicsModeInfo;
  447. BEGIN
  448. Trace.String("Starting"); Trace.Ln;
  449. status := EFILib.GetMemorySize(size);
  450. TRACE(size);
  451. IF EFILib.GetNextArg(kernelFileName) & EFILib.GetNextArg(configFileName) THEN
  452. (* load the kernel file into memory *)
  453. kernelStat := LoadKernel(kernelFileName, kernelAddr, kernelSize);
  454. (* parse the configuration file and generate the boot table *)
  455. btStat := LoadBootTable(configFileName, btAddr);
  456. IF (btStat = EFI.Success) THEN
  457. (* get the configurations for the framebuffer and get the address of the corresponding framebuffer *)
  458. GetConfig("DWidth",val); i:=0; dWidth := EFILib.StringToInt(i, val);
  459. GetConfig("DHeight",val); i:=0; dHeight := EFILib.StringToInt(i, val);
  460. GetConfig("DDepth",val); i:=0; dDepth := EFILib.StringToInt(i, val);
  461. dFormat := EFIGraphicsOutput.PFBGRX8Bit; (* Displays.Mod uses BGR *)
  462. fbStat := GetFrameBuffer(dWidth,dHeight,dDepth, dFormat, fbAddr, fbSize, fbInfo);
  463. TRACE(fbAddr);
  464. (*
  465. EFIGraphicalConsole.Init;
  466. EFIGraphicalConsole.SetupConsole(fbInfo, fbAddr);
  467. *)
  468. IF (fbStat = EFI.Success) THEN
  469. (* Does not work because IntToString does not function properly for large numbers.
  470. GetConfig("DMem", val);
  471. IF (val = "") THEN
  472. Trace.String("DEBUG: fbSize:"); Trace.Int(fbSize, 0); Trace.Ln;
  473. EFILib.IntToString(fbSize, val);
  474. AddConfig("DMem", val);
  475. ELSE
  476. i:= 0;
  477. IF (fbSize # EFILib.StringToInt(i, val)) THEN
  478. Trace.String("Warning: Configurated framebuffer size DMem = ");
  479. Trace.String(val);
  480. Trace.String(" does not match actual framebuffer size of ");
  481. Trace.Int(fbSize, 0);
  482. Trace.String("."); Trace.Ln;
  483. END;
  484. END;
  485. *)
  486. ELSE
  487. Trace.String("Warning: Requested display mode ");
  488. Trace.Int(dWidth,0); Trace.String("x"); Trace.Int(dHeight,0); Trace.String("x"); Trace.Int(dDepth,0);
  489. Trace.String(" not available in BGR mode. Available modes are :"); Trace.Ln;
  490. PrintGraphicsModes; Trace.Ln;
  491. Trace.String("Continuing happily."); Trace.Ln;
  492. END;
  493. END;
  494. IF traceDebug THEN
  495. Trace.String("DEBUG: Kernel at ");Trace.Address(kernelAddr);Trace.Ln;
  496. Trace.String("DEBUG: BootTable at ");Trace.Address(btAddr);Trace.Ln;
  497. Trace.String("DEBUG: FrameBuffer at "); Trace.Address(fbAddr); Trace.Ln;
  498. (*
  499. Trace.String("DEBUG: boot table:"); Trace.Ln; Trace.Memory(bootTableBegin, bootTableEnd-bootTableBegin + 5);
  500. *)
  501. END;
  502. IF (EFILib.GetNextArg(arg) & (CHR(arg[0]) = '-') & (CHR(arg[1]) = 'd')) THEN
  503. Trace.Ln;
  504. Trace.String("Dry Run Complete"); Trace.Ln;
  505. RETURN;
  506. END;
  507. (*
  508. Trace.Memory(kernelAddress, 100);
  509. *)
  510. memmapStat := EFILib.GetMemoryMapping(adr);
  511. memmapAddr := SYSTEM.VAL(ADDRESS,adr);
  512. TRACE(memmapAddr);
  513. TRACE(fbAddr);
  514. IF (memmapStat = EFI.Success ) THEN
  515. Trace.Ln;
  516. Trace.String("saved memory mappings");
  517. ELSE
  518. Trace.Ln;
  519. Trace.String("failed to saved memory mappings");
  520. END;
  521. PrintGraphicsModes; Trace.Ln;
  522. IF ((kernelStat = EFI.Success) OR (kernelStat = EFI.WarnWriteFailure)) & (btStat = EFI.Success) THEN
  523. TRACE(kernelAddr, btAddr, kernelSize, fbAddr);
  524. Trace.String("Shutting down Boot Services - WTF?!"); Trace.Ln;
  525. TRACE(fbInfo);
  526. status := EFILib.ExitBootServices();
  527. IF status = EFI.Success THEN
  528. (* sshhhhhht!!! nomore EFITrace from here on *)
  529. ASSERT(fbInfo # NIL);
  530. Machine.JumpTo(kernelAddr, btAddr (* eax *) , kernelSize (* esi *) , fbAddr (* edi *), memmapAddr (* ecx *), SYSTEM.VAL(ADDRESS, fbInfo)(* edx *) );
  531. Trace.String("returned ??"); Trace.Ln;
  532. (*
  533. SYSTEM.MOVE(kernelAddr, kernelAddress, kernelSize);
  534. kernelAddr := kernelAddress;
  535. IF (kernelStat = EFI.WarnWriteFailure) THEN
  536. (* couldn't allocate suitable memory portion before. Relocate it to the correct load address, EFI is not running anymore! *)
  537. END;
  538. Machine.JumpTo(kernelAddr, btAddr, 0, fbAddr);*)
  539. ELSE
  540. Trace.String("Could not exit boot services"); Trace.Ln;
  541. END;
  542. ELSE
  543. Trace.String("Error! ");
  544. IF ~((kernelStat = EFI.Success) OR (kernelStat = EFI.WarnWriteFailure)) THEN
  545. Trace.String("Kernel could not be loaded. ");
  546. END;
  547. IF ~(btStat = EFI.Success) THEN
  548. Trace.String("Boot table could not be loaded. ");
  549. END;
  550. Trace.String("Aborting"); Trace.Ln;
  551. END;
  552. ELSE
  553. Trace.String("Arguments not correct. Usage:");Trace.Ln;Trace.String("name.efi kernel config"); Trace.Ln;
  554. END;
  555. (* If we come here, something went wrong! Cleanup the memory, such that we can try another time *)
  556. EFILib.FreeMemory;
  557. END LoadA2;
  558. BEGIN
  559. LoadA2;
  560. END EFIA2Loader.
  561. PET.Open EFI.Tool ~