NB: I’ve cleaned up this guide and moved it, and I’ll continue to update it there. This blog post will not get any more updates.
Those of you who have chatted with me over the past… er… 18 months or so… know I’ve been wanting a new laptop for a while. Those of you who have chatted with me over the past 6 months know that I’d settled on a 13″ MacBook, but I wanted to wait until Apple’s next refresh/update before making the purchase.
Apple updated their laptop line at WWDC in June 2009, and I was pretty much perfectly sold on the 13″ MacBook Pro (one of the “updates” was to rebrand the 13″ aluminum unibody MacBooks as Pro models).
I was in Maryland for a wedding, and decided to take advantage of the lower tax rate (than California’s) and my sister’s educational discount (she’s a teacher). As a nice bonus of the edu pricing, I also got a free 8GB iPod Touch (which I really like a lot more than I expected to).
So ok, enough background.
Vital stuff: this describes my experience installing Linux on a June 2009 era MacBook Pro 13″. DMI reports that this model name is “MacBookPro5,5″. This guide may work for other similar systems, or it may not.
lspci output for this laptop:
00:00.0 Host bridge: nVidia Corporation Device 0a82 (rev b1)
00:00.1 RAM memory: nVidia Corporation Device 0a88 (rev b1)
00:03.0 ISA bridge: nVidia Corporation Device 0aae (rev b3)
00:03.1 RAM memory: nVidia Corporation Device 0aa4 (rev b1)
00:03.2 SMBus: nVidia Corporation Device 0aa2 (rev b1)
00:03.3 RAM memory: nVidia Corporation Device 0a89 (rev b1)
00:03.4 RAM memory: nVidia Corporation Device 0a98 (rev b1)
00:03.5 Co-processor: nVidia Corporation Device 0aa3 (rev b1)
00:04.0 USB Controller: nVidia Corporation Device 0aa5 (rev b1)
00:04.1 USB Controller: nVidia Corporation Device 0aa6 (rev b1)
00:06.0 USB Controller: nVidia Corporation Device 0aa7 (rev b1)
00:06.1 USB Controller: nVidia Corporation Device 0aa9 (rev b1)
00:08.0 Audio device: nVidia Corporation Device 0ac0 (rev b1)
00:09.0 PCI bridge: nVidia Corporation Device 0aab (rev b1)
00:0a.0 Ethernet controller: nVidia Corporation MCP79 Ethernet (rev b1)
00:0b.0 IDE interface: nVidia Corporation Device 0ab5 (rev b1)
00:10.0 PCI bridge: nVidia Corporation Device 0aa0 (rev b1)
00:15.0 PCI bridge: nVidia Corporation Device 0ac6 (rev b1)
00:16.0 PCI bridge: nVidia Corporation Device 0ac7 (rev b1)
02:00.0 VGA compatible controller: nVidia Corporation Device 0863 (rev b1)
03:00.0 Network controller: Broadcom Corporation BCM4322 802.11a/b/g/n Wireless LAN Controller (rev 01)
04:00.0 FireWire (IEEE 1394): Agere Systems Device 5901 (rev 07)
I decided to put Gentoo (the x86_64 version) on it. So, I grabbed the latest minimal installer (dated 20090618) and booted it. I was disappointed to find that the keyboard didn’t work after boot, so I couldn’t go anywhere with it. I Googled around a bit, but wasn’t able to find anything (except for the possibility of the usbhid driver failing to load due to an unrecognised option, which I thought a bit unlikely). After some head-scratching, I downloaded the install/live CD of Ubuntu 9.04, and booted that. To my happiness, the keyboard was working fine.
Backing up a little… Before booting the Linux CD, first I installed rEFIt from inside MacOS X. I didn’t burn the rEFIt bootable CD; I just went ahead and used the Mac installer which did the job without rebooting. After that I could still boot other CDs by holding down the “c” key while booting, but if I didn’t, I got a nifty boot menu with MacOS X listed.
I decided I wanted to keep my MacOS X partition, so I fired up Disk Utility and resized the HFS+ MacOS partition down to 40GB. Yes, amazingly, current Leopard (10.5.7) Disk Utility can resize the startup volume while MacOS is running, without needing to use the installer DVD or reboot at all. It just resizes it live and you’re done. It was very quick, too.
BIOS Mode and Partitioning
I’ve read various sources that said that the proprietary nvidia drivers would not work with the machine in native EFI mode (though this seems to suggest otherwise, but I haven’t tried it), so it would have to be booted in BIOS mode. Unfortunately, this makes partitioning the drive a little annoying, as I wanted to keep MacOS X to dual-boot. The GPT partition table layout has a legacy MBR mode for booting BIOS-mode OSes (in our case, grub is the legacy OS).
The MBR compatibility mode only supports four primary partitions, and no extended partitions, so the partition with your kernel on it needs to be one of the first four. Since Apple takes up the first two partition slots (I’m told MacOS X will boot without the first partition, but it’s unclear as to whether or not missing that partition will screw up Apple-supplied updates later), that leaves two left. Plenty. Three and four ended up being /boot (96MB), and / (around 60GB). Initially, I was debating leaving out the swap partition, but Linux’s suspend to disk (aka hibernate) requires a swap partition, so I allocated 4GB for it. The rest of the space I allocated for /home. I used ext3 for the root and home partitions, since I don’t trust ext4 yet, and tools for manipulating ext4 volumes from other OSes are currently nonexistent. For the boot partition I used ext2, and set ‘noauto’ in the mount options so it doesn’t get mounted unless I tell it to. Note that *all* of these partitions should be primary partitions. GPT doesn’t use anything else. Grub will only be able to see my first two Linux partitions (/boot and /), but that’s fine, as the kernel will be on /boot, and once Linux comes up it will know how to read the real GPT partition table to find the rest of the partitions.
After partitioning, I rebooted and selected the GPT/MBR partition table sync item from the rEFIt boot menu. This turned out to be unnecessary for me (I think gparted did it for me?), but this might be needed in some cases.
After partitioning, I pretty much followed the normal Gentoo install procedure (downloading a stage3 tarball, unpacking it to the root partition, chrooting, setting up a new kernel and various stuff, installing grub, and rebooting). It was remarkably painless. After the reboot, the rEFIt boot menu had an entry for Linux (with a cute penguin icon) next to the MacOS X entry, so I selected that and booted.
I started off with the gentoo-sources-2.6.30-r1 kernel (and just today updated to -r2 with no trouble). Here’s my kernel config. I set up the uvesafb framebuffer console driver, which seems to work great.
I installed nvidia-drivers-180.60. Previous versions did not compile against the 2.6.30 kernel. I created a minimal /etc/X11/xorg.conf file that only had 4 lines in it to set the video driver to “nvidia” and let the X server auto-config the rest. It appears to work fine; came up the first time at 1280×800 automatically. I didn’t test the external monitor support, as I don’t have any DisplayPort devices, and I didn’t buy the DVI adapter.
The backlight didn’t work at first, because it looks for specific MBP models, and this new laptop has a newer model number. I simply patched the ‘mbp-nvidia-bl’ driver (update: see below for a better patch) in the kernel to add “MacBookPro5,5″ as a recognised model. However, the backlight controls for some reason do not work while X is running. I suspect the nvidia driver to be at fault here, but more investigation is needed. I’m going to give nouveau a try at some point to see if this fixes any issues (though of course I’ll lose 3D accel with that).
Update (2009/07/14): The ‘nvclock’ program is able to set the backlight brightness while X is running, so I ‘ported’ the code that does that to the kernel driver. It’s not the best patch in the world, but it’s here if you want to give it a try. I’m told that this is not really a correct way of fixing the problem, as it’s not reasonable to poke at memory addresses owned/reserved by another driver (nvidia, in this case). So expect that some weirdness might occur if you use my patch.
The keyboard illumination works. The ‘applesmc’ driver detects it and creates a LED-class device (you can see it in /sys/class/leds). The ‘pommed’ daemon is supposed to support this, but I haven’t tried it yet because it requires patching to support the “MacBookPro5,5″ string. Otherwise I can manually set the keyboard lighting via the sysfs interface (just to verify it works). The ‘pommed’ daemon will monitor the light sensor and adjust the keyboard brightness accordingly. I needed to patch it to get it to recognise the new model string. Apparently upstream already has a patch and support will work in the next release. I also patched it to increase some ridiculously-stupid battery-wasting 200ms timeouts into equally-useful 2s timeouts. Ideally it shouldn’t poll at all, but I don’t care enough to put in the work to make that happen.
The touchpad works with the ‘bcm5974′ kernel driver and xf86-input-synaptics X.org driver. Note that to make X.org correctly use the synaptics driver when you aren’t providing an xorg.conf file, you need a very recent version of the hal-info package (otherwise it will use the evdev driver). I also have a custom .fdi file to specify some extra options for the driver. Left click works, and 2-finger clicking for right click and 3-finger clicking for middle click work as well. Two-finger horizontal and vertical scrolling work fine. One major annoyance is drag and drop: with MacOS running, I can click and hold with my thumb, and drag with my index finger (while keeping my thumb still). With Linux, I have to click and drag with the same finger, which is very awkward. I filed a feature request about this.
The WiFi works, but unfortunately not with the open source ‘b43′ driver, as that driver does not yet support Broadcom 802.11n chipsets. Broadcom provides a closed-source proprietary driver which seems to work decently, though the speeds I’m getting aren’t great, and it has a lot of trouble finding my 5GHz 11n AP sometimes (it finds the 2.4GHz 11g AP just fine though). Udev initially assigned the device the “eth1″ name, which I didn’t like, so I edited /etc/udev/rules.d/70-persistent-net.rules to change it to “wlan0″. NetworkManager works, though intermittently it won’t be able to find any APs (despite the fact that “iwlist wlan0 scan” shows APs). I anxiously await support from the ‘b43′ driver.
When compiling the Broadcom ‘wl’ driver, be sure to read the README on their website. The compilation is a little weird as they only provide a stub Makefile for use with the kernel’s build system. You’ll probably want to add ‘wl’ to /etc/conf.d/modules (or /etc/modules.autoload.d/kernel-2.6) to get loaded on startup. You may want to add ‘b43′ and ‘ssb’ to the blacklist in /etc/modprobe.d to be safe. If even the ssb driver gets loaded (even if b43 is not loaded), wl won’t work.
One oddity: wl requires the full suite of lib80211 helper modules, including the crypto ones. For some reason these don’t get built properly unless you compile another driver into the kernel that needs them, like CONFIG_HOSTAP (you can just compile it as a module).
The bluetooth chipset is detected, using the standard ‘btusb’ driver. I haven’t tested functionality yet because Bluez 4 is giving me issues.
The iSight works just fine with the ‘uvcvideo’ module. Interestingly, on this laptop I did not have to extract the firmware from Apple’s MacOS X driver. Oddly, sometimes the driver for it fails to load properly, complaining about not finding a “video chain” or something similar, but removing and reloading the driver usually fixes it (very occasionally a reboot seems to be required).
I haven’t been able to get sound to work yet. The snd-hda-intel driver appears to detect the device, and I can unmute it and change the volume, but playing .wav files using aplay doesn’t produce sound. I didn’t get any output from the dual-purpose audio in/out jack either. I’ve tried the patch here, as well as trying ALSA’s git repository, but no luck. My current guess is that Apple decided to use a new sound chip. I filed an issue report with ALSA here. My bug hasn’t appeared to gain any attention, but someone else’s post to alsa-devel has gotten some response, so it looks like this is being worked on.
Update (2009/07/10): There’s now experimental support for the Cirrus Logic codec in the hda-cirrus branch of Takashi Iwai’s sound-unstable-2.6 tree. I imagine this’ll end up in 2.6.31 or .32. I haven’t tried it yet, but it’s been reported to work on the MacBookPro5,5 (and was indeed the motivation for writing the codec support).
Update (2009/07/12): The new driver works for me, though the sound-unstable-2.6 tree is based on 2.6.31rc1 as of this writing, so it’s a little bit of a pain because neither the Broadcom wl driver nor the nvidia binary driver compile correctly against it. I whipped up a couple patches and submitted them to Gentoo’s bug tracker (for broadcom-sta, for nvidia-drivers), so hopefully they’ll get included in the portage tree soon (and presumably added to future releases). Here’s my new kernel config; you just need hda-intel with Cirrus Logic codec support. You could also compile it into the kernel, but I’ve left it as modules for now.
Update (2009/07/16): I wish I’d tested this first off, because suspend at least worked perfectly out of the box. No tweaks necessary. I just installed pm-utils and suspended via HAL (using xfce4-power-manager in my case). I imagine calling ‘pm-suspend’ from the command line would work as well.
Shutdown and reboot do not work. The system just halts and locks up. You’ll need to hold down the power button for 5 seconds to shut it off. On a rare occasion shutdown will actually power off the unit, but reboot has never worked. I suspect that dropping the BIOS emulation and booting in EFI mode will solve this problem.
USB works fine for mass storage devices, at least. The SD card reader is detected as a usb-storage device, and works as it should.
Firewire drivers load (I used the kernel’s “new” firewire stack) and detect the chipset just fine, but I don’t have any devices to test it with.
This laptop has an accelerometer (aka Apple Motion Sensor). It appears to work; I can read the machine’s orientation via sysfs, but I don’t know if there are any daemons that will watch it and park the heads on the hard drive if the laptop gets shaken/dropped. There are also other nifty things you can do with it that I haven’t tried.
All things considered, I’m pretty happy. I haven’t gotten to a point where I can give meaningful battery life numbers, but I’ll try to get to that soon. The machine seems to run pretty cool and quiet, even while compiling for a while. My only major outstanding issue is sound.
BIOS mode vs. EFI mode
In order to get shutdown and reboot working, I’ve been trying to boot in EFI mode, with no success yet. I’ve tried the latest SVN versions of grub2, but I’ve had a lot of trouble. rEFIt only seems to find grub.efi if I put it on the HFS+ MacOS X partition; if put it on the Linux partition, it doesn’t work. Running rEFIt’s EFI console and poking at the disk partitions seems to indicate that it’s failing to read the ext3 partitions for some reason.
Grub2 otherwise just seems very buggy. The config file parsing doesn’t appear to work (when grub2 loads, it prints messages about “menuentry” being an invalid command). Despite the fact that linux.mod is loaded, “linux” isn’t being recognised as a valid command. In fact, after I use many commands once, successive uses claim that the command is invalid. Even the “help” command doesn’t work (fortunately, hitting the tab key lists valid commands). I’ve mostly given up on grub2. One of the nice things about grub2 is that, if you boot in BIOS mode, you can dump your main and video BIOS images which grub2 can later load/emulate on bootup in EFI mode, which presumably would allow the nvidia drivers to work correctly.
So next I’ll be giving elilo a try. It apparently doesn’t have support for loading BIOS images, but maybe I can get that to work eventually.