Skip to content

Commit

Permalink
enable, fix and document EDK2 Linux compilation
Browse files Browse the repository at this point in the history
* Still to be considered EXPERIMENTAL at this stage
  • Loading branch information
pbatard committed Jul 30, 2017
1 parent 7a77e5f commit f21803f
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Expand Up @@ -2,6 +2,7 @@
* text=auto
# git apply may fail unless it is fed LF terminated patches...
*.patch eol=lf
*.sh eol=lf
*.c text
*.h text
*.md text
Expand Down
1 change: 1 addition & 0 deletions EfiFsPkg/Affs.inf
Expand Up @@ -71,3 +71,4 @@
*_*_*_CC_FLAGS = -Os -DCPU_$(ARCH) -DGRUB_FILE=__FILE__ -DDRIVERNAME=$(BASE_NAME) -DDRIVERNAME_STR="\"Amiga FFS\""
# On MSFT compilers, we must force-disable the default /GL option in order to replace the memset() intrinsic
MSFT:*_*_*_CC_FLAGS = /GL- /wd4028 /wd4068 /wd4133 /wd4146 /wd4201 /wd4204 /wd4244 /wd4245 /wd4267 /wd4311 /wd4312 /wd4334 /wd4706
GCC:*_*_*_CC_FLAGS = -Wno-overflow
83 changes: 63 additions & 20 deletions README.md
Expand Up @@ -9,37 +9,51 @@ For additional info as well as precompiled drivers, see http://efi.akeo.ie
## Requirements

* [Visual Studio 2017](https://www.visualstudio.com/vs/community/) (Windows), MinGW (Windows), gcc (Linux) or
[EDK2](https://github.com/tianocore/edk2)/VS2015 (Windows). Note that EDK2 is supported with the Visual
Studio compiler __only__.
[EDK2](https://github.com/tianocore/edk2).
* A git client able to initialize/update submodules
* [QEMU](http://www.qemu.org) __v2.7 or later__ if debugging with Visual Studio
(NB: You can find QEMU Windows binaries [here](https://qemu.weilnetz.de/w64/))

## Compilation

* [_Common_] Fetch the git submodules with `git submodule init` and `git submodule update`.
* [_Common_] Apply the included f2fs patch to the `grub\` subdirectory. This adds F2FS support,
which is not yet included in GRUB2.
* [_Visual Studio_] Apply the other patches to the `grub\` subdirectory. If you are using Clang/C2
you can apply the first patch only. If you are using MSVC, you must apply 2 patches and if you
are using EDK2 you should apply all of them.
* [_Visual Studio_] Open the solution file and hit `F5` to compile and debug the default driver.
* [_EDK2_] Open and elevated command prompt and create a symbolic link, inside your
EDK2 directory, to the EfiFs source. For instance, if you have EKD2 in `C:\edk2` and EfiFs in `C:\efifs`,
youd should run `mklink /D EfiFsPkg C:\efifs` inside the `C:\edk2` directory.
* [_EDK2_] Open a Visual Studio command prompt and, after having invoked `Edk2Setup.bat` run something like:
### Common

* Fetch the git submodules with `git submodule init` and `git submodule update`.
* Apply the included f2fs patch to the `grub\` subdirectory. This adds F2FS support, which is not
yet included in GRUB2.
* Apply the other patches to the `grub\` subdirectory.

### Visual Studio (non EDK2)

* Open the solution file and hit `F5` to compile and debug the default driver.

### gcc (non EDK2)

* Run `make` in the top directory. If needed you can also issue something like
`make ARCH=<arch> CROSS_COMPILE=<tuple>` where `<arch>` is one of `ia32`, `x64`, `arm` or
`aa64` (the __official__ UEFI abbreviations for an arch, as used in `/efi/boot/boot[ARCH].efi`)
and tuple is the one for your cross-compiler, such as `arm-linux-gnueabihf-`.
e.g. `make ARCH=aa64 CROSS_COMPILE=aarch64-linux-gnu-`

### EDK2

* Open an elevated command prompt and create a symbolic link called `EfiFsPkg`, inside your EDK2
directory, to the EfiFs source. On Windows, from an elevated prompt, you could run something like
`mklink /D EfiFsPkg C:\efifs`, and on Linux `ln -s ../efifs EfiFsPkg`.
* From a command prompt, set Grub to target the platform you are compiling for by invoking:
* (Windows) `set_grub_cpu.cmd <arch>`
* (Linux) `./set_grub_cpu.sh <arch>`
Where `<arch>` is one of `ia32`, `x64`, `arm` or `aa64`.
Note that you __MUST__ invoke the `set_grub_cpu` script __every time you switch target__.
* After having invoked `Edk2Setup.bat` (Windows) or `edksetup.sh` (Linux) run something like:
```
build -a X64 -b RELEASE -t VS2015 -p EfiFsPkg/EfiFsPkg.dsc
build -a X64 -b RELEASE -t <toolchain> -p EfiFsPkg/EfiFsPkg.dsc
```
where `<toolchain>` is something like `VS2015` (Windows) or `GCC5` (Linux).
NB: To build an individual driver, such as NTFS, you would can also use something like:
```
build -a X64 -b RELEASE -t VS2015 -p EfiFsPkg/EfiFsPkg.dsc -m EfiFsPkg/EfiFsPkg/Ntfs.inf
build -a X64 -b RELEASE -t <toolchain> -p EfiFsPkg/EfiFsPkg.dsc -m EfiFsPkg/EfiFsPkg/Ntfs.inf
```
* [_gcc_] Run `make` in the top directory. If needed you can also issue something like
`make ARCH=<arch> CROSS_COMPILE=<tuple>` where `<arch>` is one of `ia32`, `x64`, `arm` or
`aa64` (the __official__ UEFI abbreviations for an arch, as used in `/efi/boot/boot[ARCH].efi`)
and tuple is the one for your cross-compiler, such as `arm-linux-gnueabihf-`.
e.g. `make ARCH=aa64 CROSS_COMPILE=aarch64-linux-gnu-`

## Testing

Expand Down Expand Up @@ -76,3 +90,32 @@ While in this section, you may also want to select the installation of _Clang/C2
This is a pure GPLv3+ implementation of EFI drivers. Great care was taken
not to use non GPLv3 compatible sources, such as rEFInd's `fsw_efi` (GPLv2 only)
or Intel's FAT driver (requires an extra copyright notice).

## Bonus: Commands to compile EfiFs using EDK2 on Debian GNU/Linux 9.1

As root:
```
apt-get install nasm uuid-dev gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
cd /usr/src
git clone https://github.com/tianocore/edk2.git
git clone https://github.com/pbatard/efifs.git
cd efifs
git submodule init
git submodule update
cd grub
git am ../*.patch
cd /usr/src/edk2
ln -s ../efifs EfiFsPkg
make -C /usr/src/edk2/BaseTools/Source/C
export GCC5_ARM_PREFIX=arm-linux-gnueabihf-
export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
source edksetup.sh
./EfiFsPkg/set_grub_cpu.sh X64
build -a X64 -b RELEASE -t GCC5 -p EfiFsPkg/EfiFsPkg.dsc
./EfiFsPkg/set_grub_cpu.sh IA32
build -a IA32 -b RELEASE -t GCC5 -p EfiFsPkg/EfiFsPkg.dsc
./EfiFsPkg/set_grub_cpu.sh ARM
build -a ARM -b RELEASE -t GCC5 -p EfiFsPkg/EfiFsPkg.dsc
./EfiFsPkg/set_grub_cpu.sh AARCH64
build -a AARCH64 -b RELEASE -t GCC5 -p EfiFsPkg/EfiFsPkg.dsc
```
22 changes: 12 additions & 10 deletions set_grub_cpu.cmd
@@ -1,19 +1,21 @@
@echo off

set ARCH=
if "%1"=="Win32" set ARCH=i386
if "%1"=="x64" set ARCH=x86_64
if "%1"=="ARM" set ARCH=arm
if "%1"=="ARM64" set ARCH=arm64
if /I "%1"=="win32" set ARCH=i386
if /I "%1"=="ia32" set ARCH=i386
if /I "%1"=="x64" set ARCH=x86_64
if /I "%1"=="arm" set ARCH=arm
if /I "%1"=="arm64" set ARCH=arm64
if /I "%1"=="aa64" set ARCH=arm64
if "%ARCH%"=="" (
echo Unsupported arch %1
exit 1
)
echo %ARCH%
echo Setting GRUB for %ARCH%...

if not exist "cpu\%ARCH%" (
echo Duplicating GRUB include\grub\%ARCH%\ to include\grub\cpu\
rmdir /S /Q cpu >NUL 2>&1
xcopy "%ARCH%" "cpu" /i /q /s /y /z
echo %ARCH% > cpu/%ARCH%
if not exist "%~dp0\grub\include\grub\cpu\%ARCH%" (
echo Duplicating grub\include\grub\%ARCH%\ to grub\include\grub\cpu\
rmdir /S /Q "%~dp0\grub\include\grub\cpu" >NUL 2>&1
xcopy "%~dp0\grub\include\grub\%ARCH%" "%~dp0\grub\include\grub\cpu" /i /q /s /y /z
echo %ARCH% > "%~dp0\grub\include\grub\cpu\%ARCH%"
)
13 changes: 13 additions & 0 deletions set_grub_cpu.sh
@@ -0,0 +1,13 @@
#!/bin/bash
grub_include=`dirname $(readlink -f $0)`/grub/include/grub
shopt -s nocasematch
case "$1" in
"x64") arch=x86_64;;
"ia32") arch=i386;;
"arm") arch=arm;;
"aa64") arch=arm64;;
"aarch64") arch=arm64;;
*) echo "Unsupported arch"; exit 1;;
esac
rm -f $grub_include/cpu
ln -vs $grub_include/$arch $grub_include/cpu
7 changes: 7 additions & 0 deletions src/driver.h
Expand Up @@ -69,6 +69,13 @@
#endif
#endif

/* Sort out the platform specifics */
#if defined(_M_ARM64) || defined(__aarch64__) || defined (_M_X64) || defined(__x86_64__)
#define PERCENT_P L"%llx"
#else
#define PERCENT_P L"%x"
#endif

/* Sort out the differences between EDK2 and gnu-efi */
#if defined(_GNU_EFI)
#define STUPID_CLANG_REF(a,b) a.b
Expand Down
26 changes: 13 additions & 13 deletions src/file.c
Expand Up @@ -81,7 +81,7 @@ FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
INTN i, len;
BOOLEAN AbsolutePath = (*Name == L'\\');

PrintInfo(L"Open(%llx%s, \"%s\")\n", (UINT64) This,
PrintInfo(L"Open(" PERCENT_P L"%s, \"%s\")\n", (UINTN) This,
IS_ROOT(File)?L" <ROOT>":L"", Name);

/* Fail unless opening read-only */
Expand All @@ -101,7 +101,7 @@ FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"<ROOT>":FileName(File));
File->RefCount++;
*New = This;
PrintInfo(L" RET: %llx\n", (UINT64) *New);
PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
return EFI_SUCCESS;
}

Expand Down Expand Up @@ -138,7 +138,7 @@ FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
*New = &File->FileSystem->RootFile->EfiFile;
/* Must make sure that DirIndex is reset too (NB: no concurrent access!) */
File->FileSystem->RootFile->DirIndex = 0;
PrintInfo(L" RET: %llx\n", (UINT64) *New);
PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
return EFI_SUCCESS;
}

Expand Down Expand Up @@ -193,7 +193,7 @@ FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
NewFile->RefCount++;
*New = &NewFile->EfiFile;

PrintInfo(L" RET: %llx\n", (UINT64) *New);
PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
return EFI_SUCCESS;
}

Expand All @@ -217,7 +217,7 @@ FileClose(EFI_FILE_HANDLE This)
{
EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);

PrintInfo(L"Close(%llx|'%s') %s\n", (UINT64) This, FileName(File),
PrintInfo(L"Close(" PERCENT_P L"|'%s') %s\n", (UINTN) This, FileName(File),
IS_ROOT(File)?L"<ROOT>":L"");

/* Nothing to do it this is the root */
Expand Down Expand Up @@ -405,7 +405,7 @@ FileRead(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
{
EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);

PrintInfo(L"Read(%llx|'%s', %d) %s\n", (UINT64) This, FileName(File),
PrintInfo(L"Read(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This, FileName(File),
*Len, File->IsDir?L"<DIR>":L"");

/* If this is a directory, then fetch the directory entries */
Expand Down Expand Up @@ -459,7 +459,7 @@ FileSetPosition(EFI_FILE_HANDLE This, UINT64 Position)
EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
UINT64 FileSize;

PrintInfo(L"SetPosition(%llx|'%s', %lld) %s\n", (UINT64) This,
PrintInfo(L"SetPosition(" PERCENT_P L"|'%s', %lld) %s\n", (UINTN) This,
FileName(File), Position, (File->IsDir)?L"<DIR>":L"");

/* If this is a directory, reset the Index to the start */
Expand All @@ -475,7 +475,7 @@ FileSetPosition(EFI_FILE_HANDLE This, UINT64 Position)
*/
FileSize = GrubGetFileSize(File);
if (Position > FileSize) {
PrintError(L"'%s': Cannot seek to %#llx of %llx\n",
PrintError(L"'%s': Cannot seek to #%llx of %llx\n",
FileName(File), Position, FileSize);
return EFI_UNSUPPORTED;
}
Expand All @@ -500,7 +500,7 @@ FileGetPosition(EFI_FILE_HANDLE This, UINT64 *Position)
{
EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);

PrintInfo(L"GetPosition(%llx|'%s', %lld)\n", (UINT64) This, FileName(File));
PrintInfo(L"GetPosition(" PERCENT_P L"|'%s', %lld)\n", (UINTN) This, FileName(File));

if (File->IsDir)
*Position = File->DirIndex;
Expand Down Expand Up @@ -528,9 +528,9 @@ FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data)
EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *VLInfo = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Data;
EFI_TIME Time;
CHAR8* label;
INTN tmpLen;
UINTN tmpLen;

PrintInfo(L"GetInfo(%llx|'%s', %d) %s\n", (UINT64) This,
PrintInfo(L"GetInfo(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This,
FileName(File), *Len, File->IsDir?L"<DIR>":L"");

/* Determine information to return */
Expand Down Expand Up @@ -558,7 +558,7 @@ FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data)
Info->PhysicalSize = GrubGetFileSize(File);
}

tmpLen = (INTN)(Info->Size - sizeof(EFI_FILE_INFO) - 1);
tmpLen = (UINTN)(Info->Size - sizeof(EFI_FILE_INFO) - 1);
Status = Utf8ToUtf16NoAllocUpdateLen(File->basename, Info->FileName, &tmpLen);
if (EFI_ERROR(Status)) {
if (Status != EFI_BUFFER_TOO_SMALL)
Expand Down Expand Up @@ -683,7 +683,7 @@ FileFlush(EFI_FILE_HANDLE This)
{
EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);

PrintInfo(L"Flush(%llx|'%s')\n", (UINT64) This, FileName(File));
PrintInfo(L"Flush(" PERCENT_P L"|'%s')\n", (UINTN) This, FileName(File));
return EFI_SUCCESS;
}

Expand Down
2 changes: 1 addition & 1 deletion src/logging.c
Expand Up @@ -74,7 +74,7 @@ SetLogging(VOID)
LogLevel = Atoi(LogVar);

for (i=0; i<ARRAYSIZE(PrintTable); i++)
*PrintTable[i] = (i < LogLevel)?Print:PrintNone;
*PrintTable[i] = (i < LogLevel)?(Print_t)Print:(Print_t)PrintNone;

PrintExtra(L"LogLevel = %d\n", LogLevel);
}
2 changes: 1 addition & 1 deletion src/missing.c
Expand Up @@ -62,7 +62,7 @@ INT64 _allmul(INT64 a, INT64 b)
{
INT64 _a = (a>=0)?a:-a, _b = (b>=0)?b:-b;
if (((a > 0) & (b < 0)) || ((a < 0) && (b > 0)))
return -MultU64x32(_a, (UINTN)_b);
return -1LL * MultU64x32(_a, (UINTN)_b);
return MultU64x32(_a, (UINTN)_b);
}

Expand Down

0 comments on commit f21803f

Please sign in to comment.