Fog

From wikinotes

Archlinux on a macbook. Named after Dean Fog.

TODO:

these install instructions don't belong here.
I need a section for archlinux variant installs like archlinux-arm, and this alt-kernel

t2linux install docs https://wiki.t2linux.org/distributions/arch/installation/
t2linux wifi docs https://wiki.t2linux.org/guides/wifi/
t2linux pacman repo https://github.com/Redecorating/archlinux-t2-packages
arch install https://wiki.archlinux.org/title/Installation_guide#Set_the_console_keyboard_layout
systemd boot https://wiki.archlinux.org/title/Systemd-boot

Safety Net

Using the dedicated GPU 100% of the time produces lots of heat, and wasted battery life when you don't need it.
Defaulting to the dedicated graphics has been known to prevent MacOS from being able to boot.
Since Partition settings are locked into MacOS (and I'm uncertain whether I could boot from a USB),
it would be prudent to enable ssh in your MacOS install).

# MacOS
(apple) > System Preferences:
  - Security & Privacy:
    - Privacy Tab:
      - Full Disk Access:
        - +: Applications/Utilities/Terminal
# MacOS
sudo systemsetup -setremotelogin on

# you probably also want to harden your /etc/ssh/sshd_config...

Install Media

Download install media

raw (out of date) https://dl.t2linux.org/archlinux/iso/index.html
w/ wifi drivers https://github.com/t2linux/archiso-t2/releases
diskutil list
diskutil unmountDisk /dev/disk2
dd if=path/to/archlinux-version-x86_64.iso of=/dev/rdisk2 bs=1m

Partition Setup

You can't change the partition scheme from outside of macos unfortunately.

- macbook, start bootcamp (preinstalled)
  - drag slider for size (deletes apfs snapshots?)

- disk utility
  - create a partition (any format) for your linux install

- restart, holding cmd+r
  - Utilities > Startup Security Utility:
    - [x] No Security
    - [x] Allow booting from external media

- restart, holding opt
  - you don't need to connect to wifi in bootloader
  - boot from EFI

Base Install

NOTE:

Use the wifi-enabled ISO, spoke with devs and wired kernel is outdated

(archiso) wlan setup

iwctl
 device list
 station wlan0 scan
 station wlan0 get-networks
 station wlan0 connect ${SSID}

ping archlinux.org

(archiso) format && baseinstall

timedatectl set-ntp true

pacman -Sy
# pacman-key --refresh-keys

fdisk -l                  # find disk/partition
mkfs.ext4 /dev/nvme0n1p3  # format partition as ext4

mount /dev/nvme0n1p3 /mnt       # your install
mkdir -p /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot  # reuse macbook's EFI paritition

# if necesary, copy/modify /etc/pacman.conf to /mnt/pacman.conf
# and use: `pacstrap -C /mnt/pacman.conf`
pacstrap /mnt \
  base base-devel                           `# base packages/build-tools` \
  linux-t2 linux-t2-headers linux-t2-docs   `# t2-kernel` \
  efivar efibootmgr dosfstools              `# tools to manage efi` \
  linux-firmware dkms \
  apple-bcm-wifi-firmware \
  iwd networkmanager netstat-nat net-tools \
  neovim git openssh man-db

genfstab -U /mnt >> /mnt/etc/fstab
arch-chroot /mnt

(chroot) Add t2linux repo

cat << EOF >> /etc/pacman.conf
[mbp]
Server = https://dl.t2linux.org/archlinux/$repo/$arch
EOF

# you'll also likely want to enable 'multilib' repo

pacman -Syy

(chroot) Base Settings

ln -sf /usr/share/zoneinfo/America/Toronto /etc/localtime
hwclock --systohc
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
echo "fog" > /etc/hostname
mkinitcpio -P
passwd

(chroot) Bootloader

cat << EOF > /boot/loader/loader.conf
default archlinux
timeout 1
EOF

# find PARTUUID of 'archlinux' install partition
# (not EFI partition, not UUID)
blkid

cat << EOF > /boot/loader/entries/archlinux.conf
title Arch Linux
linux vmlinuz-linux-t2
initrd initramfs-linux-t2.img
# no quotes around PARTUUID
options intel_iommu=on iommu=pt pcie_ports=compat root=PARTUUID=${PARTUUID} rw
EOF

# if you cannot write /boot, use --no-variables
bootctl install

systemctl mask systemd-boot-system-token

# remount efivars as read-only (or kernel panic)
# USE EITHER: (1 works for me)
#    echo efivarfs /sys/firmware/efi/efivars efivarfs ro,remount,nofail 0 0 >> /etc/fstab
# OR
#    add 'efi=noruntime' to options in '/boot/loader/entries/archlinux.conf'

Reboot

- exit && reboot
- hold 'option' while booting to choose boot
- after selection, wait for timeout (choosing with enter seems to fail)

Debugging Boot Issues

# from archiso, specify the journal of your chroot
journalctl --directory=/var/log/journal

Post Install

Wifi Drivers

Boot into macos

curl -#O https://wiki.t2linux.org/tools/wifi.sh
chmod +x wifi.sh
./wifi.sh

Boot into linux

sudo umount /dev/nvme0n1p1
sudo mkdir /tmp/apple-wifi-efi
sudo mount /dev/nvme0n1p1 /tmp/apple-wifi-efi
bash /tmp/apple-wifi-efi/wifi.sh
sudo reboot

Now verify output of wifi driver is error-free.

sudo journalctl -k --grep=brcmfmac  # check for errors
ip link                             # check for wlan0

Now you can test a connection

systemctl start iwd
iwctl
> station wlan0 scan
> station wlan0 get-networks
> station wlan0 connect ${SSID}

Finally, use NetworkManager (for wireguard, routing) with iwd as backend

cat << EOF > /etc/NetworkManager/NetworkManager.conf
[device]
wifi.backend=iwd
EOF

sudo systemctl enable --now iwd
sudo systemctl restart NetworkManager

route               # confirm routing table present
ping archlinux.org  # test

CPU fan

Install and configure mbpfan,
monitor effectiveness with lm_sensors.

GPU

Dedicated GPU Drivers

Install GPU drivers (OSS reputably better here)

lscpi -nn | grep VGA  # find gpu

pacman -S xf86-video-ati    # oss
# or
pacman -S xf86-video-amdgpu # proprietary

Hybrid Graphics

NOTE:

If gpu-switch prevents you from booting linux,
Reset your nvram by holding: cmd+opt+p+r on boot

NOTE:

This is a huge boost for thermals, down from ~60*C idle to ~47*C

First, install the intel GPU driver driver.

pacman -S xf86-video-intel

Next, install patched bootloader

# there is an AUR package, but it is very out of date

sudo pacman -S gnu-efi

git clone https://github.com/aa15032261/apple_set_os-loader
cd apple_set_os-loader

make
sudo cp /boot/EFI/BOOT/BOOTX64.EFI /boot/EFI/BOOT/BOOTX64.EFI.orig
sudo cp ./bootx64.efi /boot/EFI/BOOT/BOOTX64.EFI

reboot and disable MacOS's System Integrity Protection

- reboot, holding cmd+r
- Utilities > Terminal
- execute: csrutil disable  # disable system integrity protection

Reboot into MacOS now, and bless the bootloader

# first mount your efi partition
sudo mkdir /Volumes/esp
sudo mount -t msdos /dev/disk0s1 /Volumes/esp

# then bless the new boot loader
sudo bless --mount /Volumes/esp --setBoot --file /Volumes/esp/EFI/BOOT/bootx64.efi

Reboot, and verify that it worked

lspci -s 00:02.0 # should list intel card

List currently active GPU

pacman -S mesa-utils
glxinfo | grep "OpenGL renderer"

Install latest gpu-switch

# there is an AUR package, but it is very out of date
#
# this is a friendly little shellscript, can change if needed.

curl https://raw.githubusercontent.com/0xbb/gpu-switch/master/gpu-switch > gpu-switch
chmod +x gpu-switch
sudo chown root:root gpu-switch
sudo mv gpu-switch /usr/bin/

Since efivars is mounted as read-only, you'll need to boot from arch-iso and run the following

sudo gpu-switch -i  # next boot uses integrated graphics
sudo gpu-switch -d  # next boot uses dedicated graphics

Reboot, and confirm intel is being used for GPU.

glxinfo | grep "OpenGL renderer"

# you should see something like:
# OpenGL renderer string: Mesa Intel(R) UHD Graphics 630 (CFL GT2)

Hybrid Graphics and Display Brightness

The brightness will be set on boot by apple_set_os-loader, you won't be able to control it.
You can dim it using xorg --display e-DP1 --brightness 0.5.

Hybrid Graphics and Suspend/Resume

After resuming from suspend, your laptop will reconnect to the dedicated-GPU.
The brightness will be broken, and your EFIVARS will be reset to boot to the dedicated-GPU rather than the integrated-GPU.
To fix, you'll need to reboot into archiso, and re-run gpu-switch -i.

To avoid overheating issues, you should disable suspend/hibernation.

# /etc/systemd/sleep.conf

[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowSuspendThenHibernate=no
AllowHybridSleep=no

Display Scaling

; ~/.Xresources

; multiples of 96
; 96 == 100%
; 192 == 200%
Xft.dpi: 144
# ~/.xinitrc
xrdb -merge ~/.Xresources

Heat/Power Optimization

TODO:

I should really write a monitor that combines:

  • cpu frequence and temperature
  • gpu in use, frequency, temperature

Even with igpu, 800MHz cpu, TLP, thermald, I still occasionally hit 60*C with non-intensive work. what's going on?

Configuration

Install and Enable

# /boot/loader/entries/archlinux.conf

# disable intel_pstate so userspace power management available.
options intel_pstate=disable # ...
# /etc/default/cpupower

# enable conservative governor, the most resistant to ramp up cpu cycles
# some others: ondemand, userspace
governor='conservative'
# find warnings with tlp (ex: warning: systemd-rfkill.service is not masked, to correct this...)
sudo tlp-stat -s

# correct warnings
sudo systemctl mask systemd-rfkill.service
sudo systemctl mask systemd-rfkill.socket

Monitoring

monitoring some usage stats

sudo i7z                           # cpu freq per core
sudo tlp-stats -p                  # power optimizations
sudo tlp-stats -t                  # temp/fan-speeds
watch eval 'sensors | head -n 10'  # cpu temps
watch eval 'cpupower frequency-info | grep "current CPU"'

Trackpad

pacman -S xf86-input-synaptics
reboot # for driver to be used

# test it out if you like
synclient AccelFactor=0.05  # smaller movements travel further

make permanent

# /etc/X11/xorg.conf.d/70-synaptics.conf

Section "InputClass"
  Identifier "touchpad"
  Driver "synaptics"
  MatchIsTouchpad "on"

  # moving mouse-pointer
  Option "AccelFactor" "0.01"
  Option "MinSpeed" "1.2"
  Option "MaxSpeed" "2.5"

  # scroll momentum speed
  Option "VertScrollDelta" "250"
EndSection

Keyboard

TODO:

perhaps a better keymap so XF86MonBrightnessUp is fired? Seems to be a different event by default
/sys/class/backlight has no entry for the intel gpu display.

# set keyboard backlight to max brightness (persists across reboots)
echo 60 > /sys/class/leds/apple::kbd_backlight/brightness

Touchbar/Function Keys

curl -X0 https://wiki.t2linux.org/tools/touchbar.sh
sudo bash touchbar.sh
sudo touchbar  # choose 2 to default to F1-F12

Proper reloading on suspend/resume

curl -#O https://wiki.t2linux.org/tools/rmmod_tb.sh
sudo chmod 755 rmmod_tb.sh
sudo chown root:root rmmod_tb.sh
sudo mv rmmod_tb.sh /lib/systemd/system-sleep

Disable Boot Sound

# MacOs
System Preferences:
  Sound:
    - [ ] Play Sound on Startup

Default Boot

Choosing default Disk

- boot macos
- apple-menu > system preferences:
  - startup disk

Choosing default EFI bootloader

# show installed bootloaders
#
#  BootOrder: 0080,0000  # boot priority
#  Boot0080:  Mac OS X   # macos boot entry
#  Boot0000:  Foo        # foo boot entry
efibootmgr

efibootmgr -o 0000,0080  # change boot priority

Audio

See https://gist.github.com/kevineinarsson/8e5e92664f97508277fefef1b8015fba#file-daemon-conf-L2

pacman -S pulseaudio pulseaudio-alsa

/usr/lib/udev/rules.d//91-pulseaudio-custom.rules

# /usr/lib/udev/rules.d//91-pulseaudio-custom.rules

SUBSYSTEM!="sound", GOTO="pulseaudio_end"
ACTION!="change", GOTO="pulseaudio_end"
KERNEL!="card*", GOTO="pulseaudio_end"

SUBSYSTEMS=="pci", ATTRS{vendor}=="0x106b", ATTRS{device}=="0x1803", ENV{PULSE_PROFILE_SET}="apple-t2.conf"

LABEL="pulseaudio_end"

/usr/share/pulseaudio/alsa-mixer/profile-sets/apple-t2.conf

# /usr/share/pulseaudio/alsa-mixer/profile-sets/apple-t2.conf
[General]
auto-profiles = no

[Mapping builtin-speaker]
description = Built-in Speaker
device-strings = front:%f
paths-output = builtin-speaker-output
channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
priority = 100
direction = output

[Mapping builtin-mic]
description = Built-in Mic
device-strings = front:%f
paths-output = builtin-mic-input
channel-map = left,center,right
priority = 100
direction = input

[Mapping codec-output]
description = Headphone
device-strings = front:%f,1
paths-output = codec-output
channel-map = left,right
priority = 100
direction = output

[Mapping codec-input]
description = Headphone Mic
device-strings = front:%f,1
paths-output = codec-input
channel-map = mono
priority = 100
direction = input

[Profile output:builtin-speaker+input:builtin-mic]
description = Built-in Speaker + Built-in Mic
output-mappings = builtin-speaker
input-mappings = builtin-mic
skip-probe = yes

[Profile output:codec-output+input:builtin-mic]
description = Headphones + Built-in Mic
output-mappings = codec-output
input-mappings = builtin-mic

[Profile output:codec-output+input:codec-input]
description = Headphones + External Mic
output-mappings = codec-output
input-mappings = codec-input

[Profile output:builtin-speaker+input:codec-input]
description = Built-in Speaker + External Mic
output-mappings = builtin-speaker
input-mappings = codec-input

/usr/share/alsa/cards/AppleT2.conf

# /usr/share/alsa/cards/AppleT2.conf
<confdir:pcm/front.conf>

AppleT2.pcm.default {
	@args [ CARD ]
	@args.CARD {
		type string
	}
	type asym
	playback.pcm {
		type plug
		ttable {
			0.0= 1
			1.3= 1
			2.1= 1
			3.4= 1
			4.0= 1
			5.5= 1
		}
		slave {
			pcm {
				type hw
				card $CARD
				device 0
			}
			channels 6
		}
	}
	capture.pcm {
		type plug
		slave.pcm {
			type hw
			card $CARD
			device 1
		}
	}
	hint.device_output 0
	hint.device_input 1
}

AppleT2.pcm.front.0 {
	@args [ CARD ]
	@args.CARD {
		type string
	}
	type asym
	playback.pcm {
		type plug
		ttable {
			0.0= 1
			1.3= 1
			2.1= 1
			3.4= 1
			4.0= 1
			5.5= 1
		}
		slave {
			pcm {
				type hw
				card $CARD
				device 0
			}
			channels 6
		}
	}
	capture.pcm {
		type plug
		slave.pcm {
			type hw
			card $CARD
			device 1
		}
	}
	hint.device_output 0
	hint.device_input 1
}
AppleT2.pcm.front.1 {
	@args [ CARD ]
	@args.CARD {
		type string
	}
	type asym
	playback.pcm {
		type hw
		card $CARD
		device 2
	}
	capture.pcm {
		type hw
		card $CARD
		device 3
	}
	hint.device_output 2
	hint.device_input 3
}
AppleT2.pcm.front.2 {
	@args [ CARD ]
	@args.CARD {
		type string
	}
	type hw
	card $CARD
	device 4
}

~/.config/pulse/daemon.conf

# ~/.config/pulse/daemon.conf
#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.

## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for
## more information. Default values are commented out.  Use either ; or # for
## commenting.

daemonize = no
; fail = yes
; allow-module-loading = yes
; allow-exit = yes
; use-pid-file = yes
; system-instance = no
; local-server-type = user
; enable-shm = yes
; enable-memfd = yes
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
; lock-memory = no
; cpu-limit = no

; high-priority = yes
; nice-level = -11

; realtime-scheduling = yes
; realtime-priority = 5

; exit-idle-time = 20
; scache-idle-time = 20

; dl-search-path = (depends on architecture)

; load-default-script-file = yes
; default-script-file = /etc/pulse/default.pa

; log-target = auto
; log-level = notice
; log-meta = no
; log-time = no
; log-backtrace = 0

; resample-method = speex-float-1
; avoid-resampling = false
; enable-remixing = yes
; remixing-use-all-sink-channels = yes
enable-lfe-remixing = yes
; lfe-crossover-freq = 0

flat-volumes = no
; flat-volumes = yes

; rlimit-fsize = -1
; rlimit-data = -1
; rlimit-stack = -1
; rlimit-core = -1
; rlimit-as = -1
; rlimit-rss = -1
; rlimit-nproc = -1
; rlimit-nofile = 256
; rlimit-memlock = -1
; rlimit-locks = -1
; rlimit-sigpending = -1
; rlimit-msgqueue = -1
; rlimit-nice = 31
; rlimit-rtprio = 9
; rlimit-rttime = 200000

; default-sample-format = s16le
; default-sample-rate = 44100
; alternate-sample-rate = 48000
; default-sample-channels = 2
; default-channel-map = front-left,front-right
default-sample-channels = 6
; default-fragments = 4
; default-fragment-size-msec = 25

; enable-deferred-volume = yes
; deferred-volume-safety-margin-usec = 8000
; deferred-volume-extra-delay-usec = 0

~/.config/pulse/default.pa

# ~/.config/pulse/default.pa
#
#!/usr/bin/pulseaudio -nF
#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.

# This startup script is used only if PulseAudio is started per-user
# (i.e. not in system mode)

.fail

### Automatically restore the volume of streams and devices
load-module module-device-restore
load-module module-stream-restore
load-module module-card-restore

### Automatically augment property information from .desktop files
### stored in /usr/share/application
load-module module-augment-properties

### Should be after module-*-restore but before module-*-detect
load-module module-switch-on-port-available

### Load audio drivers statically
### (it's probably better to not load these drivers manually, but instead
### use module-udev-detect -- see below -- for doing this automatically)
#load-module module-alsa-sink
#load-module module-alsa-source device=hw:1,0
#load-module module-oss device="/dev/dsp" sink_name=output source_name=input
#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input
#load-module module-null-sink
#load-module module-pipe-sink

### Automatically load driver modules depending on the hardware available
.ifexists module-udev-detect.so
load-module module-udev-detect
.else
### Use the static hardware detection module (for systems that lack udev support)
load-module module-detect
.endif

### Automatically connect sink and source if JACK server is present
.ifexists module-jackdbus-detect.so
.nofail
load-module module-jackdbus-detect channels=2
.fail
.endif

### Automatically load driver modules for Bluetooth hardware
.ifexists module-bluetooth-policy.so
load-module module-bluetooth-policy
.endif

.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover
.endif

### Load several protocols
load-module module-dbus-protocol
.ifexists module-esound-protocol-unix.so
load-module module-esound-protocol-unix
.endif
load-module module-native-protocol-unix

### Network access (may be configured with paprefs, so leave this commented
### here if you plan to use paprefs)
#load-module module-esound-protocol-tcp
#load-module module-native-protocol-tcp
#load-module module-zeroconf-publish

### Load the RTP receiver module (also configured via paprefs, see above)
#load-module module-rtp-recv

### Load the RTP sender module (also configured via paprefs, see above)
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
#load-module module-rtp-send source=rtp.monitor

### Load additional modules from GSettings. This can be configured with the paprefs tool.
### Please keep in mind that the modules configured by paprefs might conflict with manually
### loaded modules.
.ifexists module-gsettings.so
.nofail
load-module module-gsettings
.fail
.endif


### Automatically restore the default sink/source when changed by the user
### during runtime
### NOTE: This should be loaded as early as possible so that subsequent modules
### that look up the default sink/source get the right value
load-module module-default-device-restore

### Automatically move streams to the default sink if the sink they are
### connected to dies, similar for sources
load-module module-rescue-streams

### Make sure we always have a sink around, even if it is a null sink.
load-module module-always-sink

### Honour intended role device property
load-module module-intended-roles

### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle

### If autoexit on idle is enabled we want to make sure we only quit
### when no local session needs us anymore.
.ifexists module-console-kit.so
load-module module-console-kit
.endif
.ifexists module-systemd-login.so
load-module module-systemd-login
.endif

### Enable positioned event sounds
load-module module-position-event-sounds

### Cork music/video streams when a phone stream is active
load-module module-role-cork

### Modules to allow autoloading of filters (such as echo cancellation)
### on demand. module-filter-heuristics tries to determine what filters
### make sense, and module-filter-apply does the heavy-lifting of
### loading modules and rerouting streams.
load-module module-filter-heuristics
load-module module-filter-apply

### Make some devices default
#set-default-sink output
#set-default-source input
load-module module-combine-sink channels=6 channel_map=front-left,front-right,rear-left,rear-right,front-center,lfe