MODULE EFILib;
IMPORT SYSTEM, EFI, EFIFileProtocol, EFISimpleFS, EFILoadedImage, Trace;
TYPE Allocation = RECORD
baseAddress: EFI.PhysicalAddress;
numPages: EFI.Int;
END;
TYPE PtrToLongString = POINTER TO ARRAY 1024 OF EFI.Char16;
CONST
maxAllocations = 128;
VAR
allocations : ARRAY maxAllocations OF Allocation;
numAllocations : LONGINT;
args : PtrToLongString;
argLen : LONGINT;
argPos : LONGINT;
PROCEDURE AllocateMemory*(VAR addr : EFI.PhysicalAddress; numPages : EFI.Int) : EFI.Status;
VAR
status : EFI.Status;
allocationType : EFI.Int;
BEGIN
IF numAllocations < maxAllocations-1 THEN
IF addr = -1 THEN
allocationType := EFI.AllocateAnyPage;
ELSE
allocationType := EFI.AllocateAddress;
END;
status := EFI.table.BS.AllocatePages(allocationType, EFI.MTLoaderData, numPages, addr);
IF status = EFI.Success THEN
allocations[numAllocations].baseAddress := addr;
allocations[numAllocations].numPages := numPages;
INC(numAllocations);
ELSE
addr := 0;
END;
RETURN status;
ELSE
RETURN EFI.Error;
END;
END AllocateMemory;
PROCEDURE FreeMemory*;
VAR
status : EFI.Status;
i : LONGINT;
BEGIN
FOR i := 0 TO numAllocations - 1 DO
status := EFI.table.BS.FreePages(allocations[i].baseAddress, allocations[i].numPages);
END;
END FreeMemory;
PROCEDURE GetMemoryMapping*(VAR adr: EFI.PhysicalAddress) : EFI.Status;
CONST
approxMemMapSize = 2048;
VAR
MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
status : EFI.Status;
MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
MemMapElement : EFI.MemoryDescriptorPointer;
i, numEntries : EFI.Int;
hi, numcritEntries : HUGEINT;
memsize : HUGEINT;
tmp : EFI.PhysicalAddress;
BEGIN
MemMapSize := LEN(MemMap)*SYSTEM.SIZEOF(EFI.MemoryDescriptor);
status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
IF status = EFI.ErrBufferTooSmall THEN
RETURN status;
END;
adr := -1;
TRACE(status);
TRACE(adr);
status :=AllocateMemory(adr, 10);
TRACE(status);
TRACE(adr);
IF status # EFI.Success THEN
RETURN status;
END;
TRACE(status);
numcritEntries := 0;
MemMapSize := LEN(MemMap)*SYSTEM.SIZEOF(EFI.MemoryDescriptor);
status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
IF status = EFI.ErrBufferTooSmall THEN
RETURN status;
END;
numEntries := MemMapSize DIV DescriptorSize;
tmp := 0H;
memsize := 0;
FOR i := 0 TO numEntries-1 DO
MemMapElement := SYSTEM.VAL(EFI.MemoryDescriptorPointer, SYSTEM.ADR(MemMap[0])+i*DescriptorSize);
IF ( (MemMapElement.Type = EFI.MTRuntimeServicesCode) OR ( MemMapElement.Type = EFI.MTRuntimeServicesData)
OR (MemMapElement.Type = EFI.MTUnusableMemory) OR (MemMapElement.Type = EFI.MTACPIReclaimMemory)
OR (MemMapElement.Type = EFI.MTACPIMemoryNVSM) OR (MemMapElement.Type = EFI.MTMemoryMappedIO)
OR (MemMapElement.Type = EFI.MTMemoryMappedIOPortSpace) OR (MemMapElement.Type = EFI.MTPalCode)
OR (MemMapElement.Type = EFI.MTLoaderCode) OR (MemMapElement.Type = EFI.MTLoaderData)
OR (MemMapElement.Type = EFI.MTReserved)
OR (MemMapElement.Type = EFI.MTBootServicesCode) OR (MemMapElement.Type = EFI.MTBootServicesData)
)THEN
IF (tmp # MemMapElement.PhysicalStart) THEN
SYSTEM.PUT(adr+(numcritEntries*2+1+1)*8, MemMapElement.PhysicalStart);
tmp := MemMapElement.PhysicalStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize);
SYSTEM.PUT(adr+(numcritEntries*2+1+1+1)*8, tmp);
numcritEntries := numcritEntries +1;
ELSE
numcritEntries := numcritEntries -1;
tmp := MemMapElement.PhysicalStart+MemMapElement.NumberOfPages*LONG(EFI.PageSize);
SYSTEM.PUT(adr+(numcritEntries*2+1+1+1)*8, tmp);
numcritEntries := numcritEntries +1;
END;
END;
memsize := memsize + MemMapElement.NumberOfPages;
END;
FOR hi:= 0 TO numcritEntries-1 DO
SYSTEM.GET(adr+(hi*2+1+1)*8, tmp);
TRACE(tmp);
SYSTEM.GET(adr+(hi*2+1+1+1)*8, tmp);
TRACE(tmp);
END;
SYSTEM.PUT(adr,numcritEntries);
SYSTEM.PUT(adr+8,memsize);
TRACE(adr);
RETURN EFI.Success;
END GetMemoryMapping;
PROCEDURE GetMemorySize*(VAR memsize : EFI.Int64 ) : EFI.Status;
CONST
approxMemMapSize = 2048;
VAR
MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
status : EFI.Status;
MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
MemMapElement : EFI.MemoryDescriptorPointer;
i, numEntries : EFI.Int;
BEGIN
MemMapSize := LEN(MemMap)*SYSTEM.SIZEOF(EFI.MemoryDescriptor);
status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
IF status = EFI.ErrBufferTooSmall THEN
RETURN status;
END;
numEntries := MemMapSize DIV DescriptorSize;
memsize := 0;
Trace.Ln();
Trace.Address(MemMapSize);
Trace.Ln();
Trace.Address(SYSTEM.SIZEOF(EFI.MemoryDescriptor));
Trace.Ln();
Trace.Address(36);
Trace.Ln();
Trace.Address(DescriptorSize);
Trace.Ln();
Trace.Address(DescriptorVersion);
Trace.Ln();
Trace.Ln();
FOR i := 0 TO numEntries-1 DO
MemMapElement := SYSTEM.VAL(EFI.MemoryDescriptorPointer, SYSTEM.ADR(MemMap[0])+i*DescriptorSize);
memsize := memsize + MemMapElement.NumberOfPages;
END;
memsize := memsize * LONG(EFI.PageSize);
Trace.Address(LONG(EFI.PageSize));
Trace.Ln();
Trace.Hex(memsize,8);
Trace.Ln();
RETURN EFI.Success;
END GetMemorySize;
PROCEDURE ExitBootServices*(): EFI.Status;
CONST
approxMemMapSize = 2048;
VAR
MemMapSize, MapKey, DescriptorSize: EFI.Int; DescriptorVersion : EFI.Int32;
status : EFI.Status;
MemMap : ARRAY approxMemMapSize OF EFI.MemoryDescriptor;
BEGIN
MemMapSize := LEN(MemMap)*SYSTEM.SIZEOF(EFI.MemoryDescriptor);
REPEAT
status := EFI.table.BS.GetMemoryMap(MemMapSize, MemMap, MapKey, DescriptorSize, DescriptorVersion);
IF status = EFI.ErrBufferTooSmall THEN
RETURN status;
END;
status := EFI.table.BS.ExitBootServices(EFI.imageHandle, MapKey);
UNTIL status = EFI.Success;
RETURN EFI.Success;
END ExitBootServices;
PROCEDURE GetArgs*(VAR loadOptionsSize : LONGINT; VAR loadOptions : EFILoadedImage.PtrToArrayOfByte) : EFI.Status;
VAR
prot : EFI.Protocol; loadedImage : EFILoadedImage.Protocol;
status : EFI.Status;
BEGIN
status := EFI.table.BS.HandleProtocol(EFI.imageHandle, EFILoadedImage.GUID, prot);
IF status = EFI.Success THEN
loadedImage := SYSTEM.VAL(EFILoadedImage.Protocol, prot);
loadOptionsSize := loadedImage.LoadOptionsSize;
loadOptions := loadedImage.LoadOptions;
END;
RETURN status;
END GetArgs;
PROCEDURE InitArgs*() : EFI.Status;
VAR
prot : EFI.Protocol; loadedImage : EFILoadedImage.Protocol;
status : EFI.Status;
loadOptionsSize : LONGINT;
loadOptions : EFILoadedImage.PtrToArrayOfByte;
BEGIN
status := EFI.table.BS.HandleProtocol(EFI.imageHandle, EFILoadedImage.GUID, prot);
IF status = EFI.Success THEN
loadedImage := SYSTEM.VAL(EFILoadedImage.Protocol, prot);
loadOptionsSize := loadedImage.LoadOptionsSize;
loadOptions := loadedImage.LoadOptions;
args:= SYSTEM.VAL(PtrToLongString, loadOptions);
argLen := loadOptionsSize DIV 2;
argPos := 0;
WHILE (argPos < argLen) & (args[argPos] # 0) & (args[argPos] # ORD(' ')) DO
INC(argPos);
END;
ELSE
ReportError(status);
END;
RETURN status;
END InitArgs;
PROCEDURE GetNextArg*(VAR arg : ARRAY OF EFI.Char16) : BOOLEAN;
VAR
status : EFI.Status;
i : LONGINT;
BEGIN
IF args = NIL THEN
status := InitArgs();
IF (status # EFI.Success) THEN
RETURN FALSE;
END;
END;
WHILE (argPos < argLen) & (args[argPos] = ORD(' ')) DO INC(argPos); END;
i := 0;
WHILE (i < LEN(arg)) & (argPos < argLen) & (args[argPos] # 0) & (args[argPos] # ORD(' ')) DO
arg[i] := args[argPos];
INC(i); INC(argPos);
END;
RETURN (i > 0);
END GetNextArg;
PROCEDURE ReadString*(VAR buf : ARRAY OF EFI.Char16);
CONST ScanCodeNull = 0;
CharLF = 0AH;
CharCR = 0DH;
VAR key : EFI.InputKey; i : LONGINT;
status : EFI.Status;
ConIn : POINTER TO EFI.SimpleInputInterface;
ConOut : POINTER TO EFI.SimpleTextOutputInterface;
newline, cursorEnabled : BOOLEAN;
lastChar : ARRAY 2 OF EFI.Char16;
BEGIN
ConIn := EFI.table.ConIn;
ConOut := EFI.table.ConOut;
lastChar[1] := 0;
cursorEnabled := ConOut.Mode.CursorVisible;
IF (~cursorEnabled) THEN
status := ConOut.EnableCursor(ConOut, TRUE);
END;
status := ConIn.Reset(ConIn, FALSE);
newline := FALSE; i := 0;
WHILE (i < LEN(buf)-1) & (~newline) DO
status := ConIn.ReadKey(ConIn, key);
IF (status = EFI.Success) & (key.ScanCode = ScanCodeNull) THEN
IF (key.UnicodeChar # CharLF) & (key.UnicodeChar # CharCR) THEN
buf[i] := key.UnicodeChar;
lastChar[0] := key.UnicodeChar;
ELSE
buf[i] := 0H;
newline := TRUE;
lastChar[0] := key.UnicodeChar;
END;
status := ConOut.OutputString(ConOut, lastChar);
INC(i);
END;
END;
buf[LEN(buf)-1] := 0H;
IF (~cursorEnabled) THEN
status := ConOut.EnableCursor(ConOut, FALSE);
END;
END ReadString;
PROCEDURE IntToString* (CONST x : LONGINT; VAR s : ARRAY OF CHAR);
VAR i, x0, slen, start : LONGINT;
BEGIN
IF x = MIN (LONGINT) THEN
s := "-2147483648";
RETURN;
END;
slen := LEN(s)-1;
IF (slen > 11) THEN
slen := 11;
END;
s[slen] := 0X;
start := 0;
IF (x < 0) & ( slen > 0 ) THEN
x0 := -x;
s[0] := '-'; start := 1;
END;
i := slen;
WHILE ( i > start ) DO
DEC(i);
s[i] := CHR (x0 MOD 10 + 30H);
x0 := x0 DIV 10;
END;
END IntToString;
PROCEDURE StringToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
BEGIN
vd := 0; vh := 0; hex := FALSE;
IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
LOOP
IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
ELSE EXIT
END;
vd := 10*vd + d; vh := 16*vh + d;
INC (i)
END;
IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END;
IF hex THEN vd := vh END;
RETURN sgn * vd
END StringToInt;
PROCEDURE StringToLongString*(CONST str : ARRAY OF CHAR; VAR lstr : ARRAY OF EFI.Char16);
VAR strlen, lstrlen,i : LONGINT;
BEGIN
strlen := LEN(str);
lstrlen := LEN(lstr);
i := 0;
WHILE (i < strlen) & (i < lstrlen) & (ORD(str[i]) # 0) DO
lstr[i] := ORD(str[i]);
INC(i);
END;
IF lstrlen > 0 THEN
lstr[i] := 0;
END;
END StringToLongString;
PROCEDURE GetProtocol*(CONST guid : EFI.GUID; VAR prot : EFI.Protocol) : EFI.Status;
VAR
handle : EFI.Handle;
handleBuf : ARRAY 512 OF EFI.Handle;
handleBufSize, i : EFI.Int;
status : EFI.Status;
BEGIN
handleBufSize := LEN(handleBuf) * SYSTEM.SIZEOF(EFI.Handle);
status := EFI.table.BS.LocateHandle(EFI.ByProtocol, guid, 0, handleBufSize, handleBuf);
IF (status = EFI.Success) & (handleBufSize > 0) THEN
i := handleBufSize DIV SYSTEM.SIZEOF(EFI.Handle);
WHILE(i>0) DO
DEC(i);
handle := handleBuf[i];
status := EFI.table.BS.HandleProtocol(handle, guid, prot);
IF status = EFI.Success THEN RETURN EFI.Success; END;
END;
RETURN EFI.Error;
END;
RETURN status;
END GetProtocol;
PROCEDURE GetFileSize*(file : EFIFileProtocol.Protocol) : EFI.Int64;
VAR
status : EFI.Status;
infoBuf : EFIFileProtocol.FileInfo;
infoBufSize : EFI.Int;
fileSize : EFI.Int64;
BEGIN
infoBufSize := SYSTEM.SIZEOF(EFIFileProtocol.FileInfo);
status := file.GetInfo(file, EFIFileProtocol.FileInfoGUID, infoBufSize, infoBuf);
IF (status = EFI.Success) THEN
fileSize := infoBuf.FileSize;
END;
RETURN fileSize;
END GetFileSize;
PROCEDURE OpenFile*(CONST fn : ARRAY OF EFI.Char16) : EFIFileProtocol.Protocol;
VAR
status : EFI.Status;
handleBuf : ARRAY 128 OF EFI.Handle;
handleBufSize : EFI.Int;
file : EFIFileProtocol.Protocol;
done : BOOLEAN;
iter : LONGINT;
BEGIN
handleBufSize := LEN(handleBuf) * SYSTEM.SIZEOF(EFI.Handle);
status := EFI.table.BS.LocateHandle(EFI.ByProtocol, EFISimpleFS.GUID, 0, handleBufSize, handleBuf);
IF (status = EFI.Success) & (handleBufSize > 0) THEN
done := FALSE;
iter := 0;
WHILE (iter < handleBufSize DIV SYSTEM.SIZEOF(EFI.Handle)) & (~done) DO
file := OpenFileOnDevice(fn, handleBuf[iter]);
IF (file # NIL) THEN
done := TRUE;
END;
INC(iter);
END;
ELSE
file := NIL;
END;
RETURN file;
END OpenFile;
PROCEDURE OpenFileOnDevice(CONST fn : ARRAY OF EFI.Char16; deviceHandle : EFI.Handle) : EFIFileProtocol.Protocol;
VAR
root : EFIFileProtocol.Protocol;
file : EFIFileProtocol.Protocol;
protSimpleFS : EFISimpleFS.Protocol;
prot : EFI.Protocol;
status : EFI.Status;
BEGIN
file := NIL;
status := EFI.table.BS.HandleProtocol(deviceHandle, EFISimpleFS.GUID, prot);
protSimpleFS := SYSTEM.VAL(EFISimpleFS.Protocol,prot);
IF (status = EFI.Success) & (protSimpleFS # NIL) THEN
status := protSimpleFS.OpenVolume(protSimpleFS, root);
IF (status = EFI.Success) THEN
status := root.Open(root, file, fn, EFIFileProtocol.ModeRead, 0);
IF (status # EFI.Success) THEN
file := NIL;
END;
END;
END;
RETURN file;
END OpenFileOnDevice;
PROCEDURE LoadFile*(file : EFIFileProtocol.Protocol; VAR loadAddr : SYSTEM.ADDRESS) : EFI.Status;
VAR
status : EFI.Status;
fileSize : EFI.Int64;
numPages : EFI.Int;
addr : EFI.PhysicalAddress;
memSize : EFI.Int;
BEGIN
fileSize := GetFileSize(file);
numPages := SHORT(fileSize DIV EFI.PageSize) + 1;
addr := loadAddr;
status := AllocateMemory(addr, numPages);
IF status = EFI.Success THEN
loadAddr := SYSTEM.VAL(SYSTEM.ADDRESS, addr);
memSize := SYSTEM.VAL(EFI.Int, fileSize);
status := file.Read(file, memSize, loadAddr);
END;
RETURN status;
END LoadFile;
PROCEDURE ReportError*(status : EFI.Status);
BEGIN
Trace.String("Error Code: "); Trace.Int(LONGINT(status - EFI.Error), 0);
Trace.Ln;
END ReportError;
BEGIN
numAllocations := 0;
args := NIL;
END EFILib.