Gentoo Raspberry Pi 3 Model B 64-bit Installation: Jon Wilder

From Gentoo Wiki
Jump to: navigation, search

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.

CODE Start fdisk and print partitions with 'p' command
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.

CODE Create New MS-DOS Label and print partitions with 'p' command
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.

CODE Make the boot partition
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 -

CODE Print partition table with 'p' command
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'.

CODE Create the swap partition
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 -

CODE Print the partition table
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.

CODE Create 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 -

CODE Final partition table
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.

CODE Save table to SD Card and exit fdisk with the 'w' command
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 -

FILE /mnt/pi3-gentoo/etc/portage/make.conf
# 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 https://wiki.gentoo.org/wiki/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 -

FILE /mnt/pi3-gentoo/etc/fstab
# /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.

Important
Do not use -S to build a stable toolchain, arm64 moves quickly
Important
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

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.

Important
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

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

Important
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.

KERNEL
.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.