User:JWylde/Gentoo Raspberry Pi 3 Model B 64-bit Installation
Preparing The Disks
Prior to installing Gentoo on a Raspberry Pi 3 Model B, the SD card must be prepared first. We can use either fdisk or Parted to accomplish this. But before we go into that, we must first figure out what the SD card identifies as on your Gentoo system. We can do this using lsblk -
root #
lsblk
If your SD card still has NOOBS installed on it, the output from lsblk should look something like this -
root #
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 74.5G 0 disk sda1 8:1 0 2M 0 part sda2 8:2 0 128M 0 part sda3 8:3 0 4G 0 part [SWAP] sda4 8:4 0 70.4G 0 part / sdb 8:16 1 29.7G 0 disk sdb1 8:17 1 1.5G 0 part sdb2 8:18 1 1K 0 part sdb5 8:21 1 32M 0 part sdb6 8:22 1 66M 0 part sdb7 8:23 1 28.1G 0 part
In this example, this Gentoo host system uses /dev/sda as the Gentoo host system block device. /dev/sdb is the NOOBS SD card. We'll use that for our example throughout this article.
If you're using a brand new pre-formatted SD card, the output from lsblk would look like this -
root #
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 74.5G 0 disk sda1 8:1 0 2M 0 part sda2 8:2 0 128M 0 part sda3 8:3 0 4G 0 part [SWAP] sda4 8:4 0 70.4G 0 part / sdb 8:16 1 29.7G 0 disk
For our partition table, our boot partition must be a primary partition and it must be a FAT32 partition for the Raspberry Pi to boot. For the swap and root partitions, we can use standard Linux formats. Optionally, we can create an extended partition and make the swap and root partitions as logical partitions if we wish. For this installation example, all partitions will be primary partitions.
fdisk
root #
fdisk -w always /dev/sdb
The -w always switch will wipe all signatures as we create partitions. Once fdisk starts, pass the 'p' option to see the partitions currently present on the SD card.
Welcome to fdisk (util-linux 2.30).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): p
Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00058ec2
Device Boot Start End Sectors Size Id Type
/dev/sdb1 8192 3140625 3132434 1.5G e W95 FAT16 (LBA)
/dev/sdb2 3140626 62333951 59193326 28.2G 5 Extended
/dev/sdb5 3145728 3211261 65534 32M 83 Linux
/dev/sdb6 3211264 3346431 135168 66M c W95 FAT32 (LBA)
/dev/sdb7 3350528 62333951 58983424 28.1G 83 Linux
First we will pass the o command to create a new MS-DOS disk label. This will delete all partitions currently in the table.
Welcome to fdisk (util-linux 2.30).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): o
Created a new DOS disklabel with disk identifier 0x67d2396a.
Command (m for help): p
Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x67d2396a
Command (m for help):
As you can see, the o command created our new DOS disklabel and deleted all partitions.
Next, we're going to make the boot partition. First, we'll use the 'n' command to make a new partition. Then, press enter for the following three prompts. This gives you the default options of -
- p - Primary Partition
- Partition number 1
- First sector at 2048
For the last sector, we'll set it at +128M. This gives us a boot partition size of 128MiB.
Then, we'll use the 't' command to change the partition type. Select hex code 'c' to change it to a 'W95 FAT32 (LBA)' partition type. Finally, use the 'a' command to toggle on the bootable flag on partition 1.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (1-4, default 1):
First sector (2048-62333951, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-62333951, default 62333951): +128M
Created a new partition 1 of type 'Linux' and of size 128 MiB.
Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): c
Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.
Command (m for help): a
Selected partition 1
The bootable flag on partition 1 is enabled now.
Command (m for help):
Using the 'P' command, print the partition table to verify that the boot partition has been made correctly -
Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xfce09755
Device Boot Start End Sectors Size Id Type
/dev/sdb1 * 2048 264191 262144 128M c W95 FAT32 (LBA)
As we can see, we have created a bootable partition starting at sector 2048 that is 128MiB in size and is a FAT32 partition type.
Next, we'll create the swap partition. Pass the 'n' command again to create a new partition. Again, we'll press enter for the next 3 prompts to get the following default options -
- p - Primary Partition
- Partition number 2
- First sector at sector 264192
Then we will set a swap size of 2GiB by passing +2G for the last sector/size. Finally, once the second partition is created, we'll use the 't' command to change the partition type, and select hex code 82 to change our partition type to 'Linux swap / Solaris'.
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (2-4, default 2):
First sector (264192-62333951, default 264192):
Last sector, +sectors or +size{K,M,G,T,P} (264192-62333951, default 62333951): +2G
Created a new partition 2 of type 'Linux' and of size 2 GiB.
Command (m for help): t
Partition number (1,2, default 2): 2
Hex code (type L to list all codes): 82
Changed type of partition 'Linux' to 'Linux swap / Solaris'.
Command (m for help):
Now print your partition table using the 'p' command and it should look like this -
Command (m for help): p
Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xfce09755
Device Boot Start End Sectors Size Id Type
/dev/sdb1 * 2048 264191 262144 128M c W95 FAT32 (LBA)
/dev/sdb2 264192 4458495 4194304 2G 82 Linux swap / Solaris
Command (m for help):
Now for the root partition. Use the 'n' command for a new partition. Then press Enter 3 more times to go with all default options. This will set us up with a primary partition on partition 3 with the rest of the available space as the root partition.
Command (m for help): n
Partition type
p primary (2 primary, 0 extended, 2 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (3,4, default 3):
First sector (4458496-62333951, default 4458496):
Last sector, +sectors or +size{K,M,G,T,P} (4458496-62333951, default 62333951):
Created a new partition 3 of type 'Linux' and of size 27.6 GiB.
Command (m for help):
And finally, print the partition table once more and your table should look like this -
Command (m for help): p
Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xfce09755
Device Boot Start End Sectors Size Id Type
/dev/sdb1 * 2048 264191 262144 128M c W95 FAT32 (LBA)
/dev/sdb2 264192 4458495 4194304 2G 82 Linux swap / Solaris
/dev/sdb3 4458496 62333951 57875456 27.6G 83 Linux
Command (m for help):
If your partition table looks like the above, pass the 'w' command to write the table to the SD card and exit fdisk.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
root ~ $
If all is good, skip down to Create Filesystems.
Create Partitions Using Parted
Alternatively, we can also use Parted to prepare our SD card. Let's set up for optimal alignment using the -a optimal command line option. Once on the Parted command line, type 'print' to see the current partition layout:
root #
parted -a optimal /dev/sdb
GNU Parted 3.2 Using /dev/sdb Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) print Model: Mass Storage Device (scsi) Disk /dev/sdb: 15.9GB Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 4194kB 15.9GB 15.9GB primary fat32 lba (parted)
Create Filesystems
Now that our new partition table has been created, it's time to format the partitions with our file systems. We will be formatting the boot partition with FAT32 and the root partition EXT4. Finally, we will also initialize the swap partition.
Create the FAT32 boot filesystem.
root #
mkfs.vfat -F 32 /dev/sdb1
mkfs.fat 4.1 (2017-01-24)
Create the ext4 root filesystem. If you get the "/dev/sdb3 contains `gzip compressed data, max compression, from Unix' data Proceed anyway? (y,N)", hit 'y' and press enter.
root #
mkfs.ext4 -i 8192 /dev/sdb3
mke2fs 1.43.4 (31-Jan-2017) /dev/sdb3 contains `gzip compressed data, max compression, from Unix' data Proceed anyway? (y,N) y Creating filesystem with 7234432 4k blocks and 3617328 inodes Filesystem UUID: c229e329-f512-4e07-a7d9-b5e1f62f33a7 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done
Finally, initialize the swap partition.
root #
mkswap /dev/sdb2
Setting up swapspace version 1 size=2 GiB (2147479552 bytes) no label,UUID=8625c597-3a09-4aa9-aa15-38b0d713d00f
Mount Filesystem
Now that we have our file systems in place, we want to create a mount point in the host system's /mnt directory. We'll call this mount point /pi3-gentoo.
root #
mkdir -v /mnt/pi3-gentoo
mkdir: created directory '/mnt/pi3-gentoo'
Mount the SD card root partition to our new mount point -
root #
mount -v /dev/sdb3 /mnt/pi3-gentoo
mount: /dev/sdb3 mounted on /mnt/pi3-gentoo.
Change into our new pi3-root directory -
root #
cd /mnt/pi3-gentoo
Get Latest Stage 3
Now we'll fire up the lynx command line browser and go to the Gentoo download mirrors to grab the latest arm64 stage3 tarball -
root #
lynx https://www.gentoo.org/downloads/mirrors/
Select the mirror nearest you and browse to releases/arm/autobuilds/current-stage3-arm64. Select stage3-arm64-yyyymmdd.tar.bz2, press 'D', then hit Enter twice to download and save to the pi3-gentoo directory. Once downloaded, exit lynx by pressing 'Q', then press Y.
Now extract the downloaded tarball. At the time of this writing, the current stage3 is stage3-arm64-20161219.tar.bz2 -
root #
tar xvjpf stage3-arm64-20161219.tar.bz2 --xattrs --numeric-owner
Once extraction completes, /mnt/gentoo/tmp needs to be emptied. Clear it now or the the Pi will do it at boot. That may take a long time.
root #
rm -rfv /mnt/pi3-gentoo/tmp/*
Portage Tree
Download the latest Portage snapshot -
Extract Portage to SD Card -
root #
tar xjvpf portage-latest.tar.bz2 -C /mnt/pi3-gentoo/usr
Base System Configuration
Copy DNS Info
Copy the host system's DNS info to the target system -
root #
cp -L /etc/resolv.conf /mnt/pi3-gentoo/etc
Configure make.conf
Configure make.conf as follows -
# These settings were set by the catalyst build script that automatically
# built this stage.
# Please consult /usr/share/portage/config/make.conf.example for a more
# detailed example.
CFLAGS="-march=armv8-a+crc -mtune=cortex-a53 -ftree-vectorize -O2 -pipe -fomit-frame-pointer"
CXXFLAGS="${CFLAGS}"
# WARNING: Changing your CHOST is not something that should be done lightly.
# Please consult [[Changing the CHOST variable]] before changing.
CHOST="aarch64-unknown-linux-gnu"
PORTDIR="/usr/portage"
DISTDIR="/usr/portage/distfiles"
PKGDIR="/usr/portage/packages"
# This sets the language of build output to English.
# Please keep this setting intact when reporting bugs.
LC_MESSAGES=C
ACCEPT_KEYWORDS="~arm64"
VIDEO_CARDS="vc4"
INPUT_DEVICES="evdev"
Configure fstab
Configure /mnt/pi3-gentoo/etc/fstab as follows -
# /etc/fstab: static file system information.
#
# noatime turns off atimes for increased performance (atimes normally aren't
# needed); notail increases performance of ReiserFS (at the expense of storage
# efficiency). It's safe to drop the noatime options if you want and to
# switch between notail / tail freely.
#
# The root filesystem should have a pass number of either 0 or 1.
# All other filesystems should have a pass number of 0 or greater than 1.
#
# See the manpage fstab(5) for more information.
#
# <fs> <mountpoint> <type> <opts> <dump/pass>
# NOTE: If your BOOT partition is ReiserFS, add the notail option to opts.
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat noauto,noatime 1 2
/dev/mmcblk0p3 / ext4 noatime 0 1
/dev/mmcblk0p2 none swap sw 0 0
/dev/cdrom /mnt/cdrom auto noauto,ro 0 0
/dev/fd0 /mnt/floppy auto noauto 0 0
Using Crossdev to Build A Cross Compiler
root #
crossdev -t aarch64-unknown-linux-gnu
You may need to nominate an overlay to store the cross ebuilds, crossdev will let you know.
There are other parameters you can pass to crossdev too.
Do not use -S to build a stable toolchain, arm64 moves quickly
Crossdev insists that many of the files in /etc/portage/ are directories
Convert files as crossdev asks e.g.
error: please convert /etc/portage/package.env to a directory
by appending _file to the existing filename
root #
mv /etc/portage/package.env /etc/portage/package.env_file
making the directory
root #
mkdir /etc/portage/package.env
then moving package.env_file into the directory.
root #
mv /etc/portage/package.env_file /etc/portage/package.env
Rinse and repeat until crossdev is happy.
crossdev will take a while. Its building
binutils: binutils-[latest] gcc: gcc-[latest] headers: linux-headers-[latest] libc: glibc-[latest]
When crossdev completes you will have a cross toolchain
user $
$ gcc-config -l
[1] aarch64-unknown-linux-gnu-5.4.0 *
[2] x86_64-pc-linux-gnu-5.3.0
[3] x86_64-pc-linux-gnu-5.4.0 *
It will also create an arm64 target root in /usr/aarch64-unknown-linux-gnu/ This is used by cross emerge.
Pure cross compiling, other than the kernel, is out of scope of this guide.
Fetch the Raspberry Pi Firmware
The Raspberry Pi Firmware is maintained in a git repository. You will need to install git if you don't have it.
root #
emerge -av git
Don't do anything you don't need to do as root.
As your normal user, make some space in the home directory for raspberry pi
user $
mkdir raspberrypi
will do nicely.
This will be for the Raspberry Pi Firmware and kernel
user $
cd raspberrypi
user $
git clone https://github.com/raspberrypi/firmware
will fetch the Pi firmware into a directory called firmware
It will actually fetch all the history too. If you are short of space or bandwidth, a shallow clone is all that's needed.
Receiving objects: 100% (484760/484760), 6.32 GiB
A full clone is 6.3G and growing, we only need the /boot directory out of the master branch.
There is nothing to build. ~/raspberrypi/firmware/boot is used as is.
Fetch, Configure and Build the Raspberry Pi Kernel
Fetch the Raspberry Pi Kernel
Stay in raspberrypi and
user $
git clone https://github.com/raspberrypi/linux
will fetch the kernel into a directory called linux.
With absolutely no fanfare at all, 64 bit support was added to this kernel tree late in 2016. No more searching for odd patches.
Not everything has been accepted by the mainline kernel yet but its getting closer. Feel free to test for yourself.
The master branch may be broken as its commit by commit as it happens. Test if you want to. Its better to use an identified tag. At the time of writing that is rpi-4.10.y. The 4.10 mainline kernel is still at -rc status.
user $
cd linux
user $
git checkout rpi-4.10.y
Checking out files: 100% (33079/33079), done.
Branch rpi-4.10.y set up to track remote branch rpi-4.10.y from origin.
Switched to a new branch 'rpi-4.10.y'
That's the kernel source tree in place, ready for configuring and cross compiling.
Configure The Kernel
ARCH=arm64 must be specified everywhere or the kernel build system will use the HOST arch. This will destroy the arm64 .config file
As your user
user $
cd raspberrypi/linux
The bcmrpi3_defconfig is almost right as it stands. It defaults to the powersave CPU governor, which runs the Pi at 600MHz. All the governors are there. Ondemand is recommended.
user $
ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make bcmrpi3_defconfig
Either use menuconfig to change the default CPU governor, add something to the kernel command line, or change it after booting.
user $
ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make menuconfig
Search for CPU_FREQ_DEFAULT_GOV go to that location and set the default to Ondemand. Exit menuconfig, saving the change.
.config - Linux/arm64 4.10.0-rc6 Kernel Configuration
> CPU Power Management > CPU Frequency scaling ──────────────────────────────────
┌────────────────────────── CPU Frequency scaling ───────────────────────────┐
│ Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty │
│ submenus ----). Highlighted letters are hotkeys. Pressing <Y> includes, │
│ <N> excludes, <M> modularizes features. Press <Esc><Esc> to exit, <?> │
│ for Help, </> for Search. Legend: [*] built-in [ ] excluded <M> module │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ [*] CPU Frequency scaling │ │
│ │ [*] CPU frequency transition statistics │ │
│ │ [ ] CPU frequency transition statistics details │ │
│ │ Default CPUFreq governor (powersave) ---> │ │
│ │ <*> 'performance' governor │ │
│ │ -*- 'powersave' governor │ │
│ │ <*> 'userspace' governor for userspace frequency scaling │ │
│ │ <*> 'ondemand' cpufreq policy governor │ │
The kernel .config contains lots of support for hardware you don't have and possibly have never heard of. More confident readers may be tempted to trim things out now. A word of advice - don't, at least, not until the system boots.
Cross Compiling The Kernel
The kernel will not link with the gold linker. It ends with
aarch64-unknown-linux-gnu-ld: fatal error: -shared and -pie are incompatible
If you don't know what the gold linker is, you are not using it.
The build is conventional, other than telling the build system to build for arm64 and use the cross compiler.
user $
ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make -jX
Change X to the number of parallel MAKE jobs you want to run. Convention is cores+1.