Custom Kernel compilations

Well, I tried the 5.2-2015.11 tools and it got the same error. I decided to modify the source file to add the set of parentheses the compiler wants. After that, the kernel built to completion.

from drivers/platform/tegra/tegra21_clocks.c:

before:
c->state = (!is_lp_cluster() == (c->u.cpu.mode == MODE_G)) ? ON : OFF;

after:
c->state = ((!is_lp_cluster()) == (c->u.cpu.mode == MODE_G)) ? ON : OFF;

Thanks. Moving on…

Hi guys,

The fix for vgettimeofday.c is REALLY simple…

Edit arch/arm64/kernel/vdso32/Makefile and change the ccflags-y line from:

ccflags-y := -shared -fPIC -fno-common -fno-builtin -march=armv7-a

to:

ccflags-y := -shared -fPIC -fomit-frame-pointer -fno-common -fno-builtin -march=armv7-a

or:

ccflags-y := -shared -fPIC -fno-common -fno-builtin -marm -march=armv7-a

… or add -O2 or something else.

The reason? The Ubuntu toolchain compiles to the Thumb instruction set by default (i.e. -mthumb), and r7 is the Thumb frame pointer (at least from GCC’s perspective. ARM has no standard frame pointer in AAPCS for Thumb code).

Building for the ARM instruction set or without frame pointers (-O2 is where -fomit-frame-pointer becomes enabled automatically) is a reasonable solution.

Ta,
Matt S.

So after a few weeks of this is it REALLY too much effort for someone at nvidia who has built a custom kernel to spell out exactly what host platform they are using, the cross compilation tools, etc that they use? Most of us don’t have the time to become experts in all of the toolsets or arm compiler minutia but just want to be able to get started with a know good development platform to get to the real work… an hour of one developers time could save a lot of people many hours of wasted effort and make nVidia looks like a classier outfit.

@nekoxp - although I haven’t tried flashing my kernel yet, I got around this compile-time problem by using the armv8l tools from Linaro. Should that work? Doesn’t the X1 have an ARMv8? Why are we using the ARMv7 stuff if there’s an ARMv8 toolchain??

I’m looking at the exact downloaded tar file names of the pre-compiled Linaro compilers I used for building a JTX1 kernel with swap enabled (and it works). Those files are:

gcc-linaro-5.2-2015.11-x86_64_aarch64-linux-gnu.tar.xz
gcc-linaro-5.2-2015.11-x86_64_arm-linux-gnueabihf.tar.xz

Any of the “5.2” dates should work if they are the aarch64-linux and arm-linux-gnueabihf pairs from the same date. There is a lot of rapid improvement by Linaro’s developers for ARMv8/ARMv8a code generation…along with the better code conditions considered error/warning may be moving targets.

I deal with so many errors and code tweaks in a day that it can be hard to remember what issues I may have worked around, so any information on what build errors there are (in detail) helps to narrow it down.

@dsillman,

64-bit ARM isn’t really the same thing as 64-bit x86 – it is a whole new instruction set architecture and exception model, which provides compatibility with the 32-bit ARM instruction set architecture(s) and exception model by allowing processors to be configured at different exception levels to run in the different execution states.

For Intel x86 and x86-64, you can use the same compiler as they have exactly the same instruction set, the same exception model, the difference is really in the extensions that bring it up to ‘64-bit’. For GCC you can pass -m32 or -m64 and generate code for either with the same toolchain, and it selects the 64-bit register set and a slightly different ABI.

For ARMv7 and AArch32 there are two instruction sets with only slightly different ABI, too – ARM and Thumb (or A32 and T32 in ARMv8 terms). You can switch between them on an “ARM” compiler using -mthumb and -marm. The registers are the same, but Thumb is a variable-length instruction set, either 16 or 32-bit opcodes, with the 16-bit opcodes having limited access. Switching between the A32 and T32 instruction sets at runtime is possible with “Branch and Exchange” (BX or BLX) instructions.

For Aarch64 and the A64 instruction set the only way to switch to the A32/T32 instruction sets (execution state) is to change exception level. That’s something a compiler simply cannot do (but it is what the VDSO code is doing in the code that’s broken - the SVC call will cause an exception from AArch32 User Mode (EL0) to AArch64 EL1.)

For ARMv8, building for AArch64 A64 or AArch32 A32/T32 you need two different compilers. The architecture version isn’t relevant in this case for the code we’re looking at – AArch32 state under ARMv8 is basically ARMv7 with the Virtualization and LPAE extensions, plus a few extra instructions. Building with an ARMv7 compiler is fine since the VDSO code has absolutely no use or access to these extensions (they’re only worthwhile at higher privilege levels, VDSO runs at User/EL0). You could actually even use an ARMv5T compiler or change the cc-flags line to -march=armv5t on your current compiler and it would build identical code. At the moment the VDSO code is built with -march=armv7-a so having a compiler capable of generating ARMv8 A32/T32 instructions – the very few that a compiler could actually generate for useful cases (dc zva for example, there’s no chance of a compiler knowing an AES encryption idiom and using aese/aesmc or the crc instructions) – has limited value, as it’s being restricted.

The key point is that GCC is configured at build-time to pre-select some options. That’s really how you get an “armv8l-linux-gnueabihf-” toolchain, it is preselected to build with “-marm -march=armv8-a+crc -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard” or something to that effect since that’s what Linaro have decided their target processor features for the default options are.

For Ubuntu toolchains (arm-linux-gnueabihf-) it’s much the same but they pick “-mthumb -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard” – the real reason is that it isn’t necessary to litter every package with those options, so that all packages are compatible with the lowest-common-denominator ARMv7 VFPv3 platform (which turns out to be nVidia Tegra and Tegra2, and a few Marvell SoCs :) and will build simply by using “gcc -c x.c -o x.o” with those options.

You can, still, build non-FPU soft-float linkage ARMv4 code with that toolchain (-marm -march=armv4 -msoft-float) but the defaults are the defaults.

Therefore you need to know which options are picked by default to override them and build the right code. Knowledge of the ABI in use (A32 and T32 are ever-so slightly different) is important when you stop using C code and start using assembly or inline assembly, and assuming that the compiler builds for the ARM/A32 ISA is poor on the part of whoever wrote the 32-bit VDSO code.

Ta,
Matt S.

Thanks for this explanation. I went back to using the arm-linux-gnueabihf- toolchain for the CROSS32CC requirement, made the Makefile fix and am now able to build the kernel successfully (and it even ran when I programmed the dev board!).

I did notice another anomaly in their build process (as described in their documentation). The apply_binaries script assumes the latest dtb files are in the kernel/dtb folder but nothing has put them there. I copied them there myself after the build (from kernel/arch/arm64/boot/dts) and everything seemed to work.

Only valid solution so far… Ty m8 !!