How to configure dual boot NixOS with Mac OS X on an (U)EFI MacBook?

This is an updated version of my initial answer, it should work for NixOS 15.09. It contains minor modifications compared to the initial version which i used to install NixOS 14.04 with some help from nix-dev mailing list.

Initial setup

  1. MacBook 5,1 (2008) with Mac OS 10.9 and hard drive partitioned as follows:

    a) 200MB EFI System Partition labelled "EFI".

    b) Two partitions used by Mac OS (10.9).

    c) Two empty ext4 partitions labelled "nixos" and "home", and a Linux Swap partition labelled "swap".

    I used the following tools:

    • GPT fdisk (from under Mac OS),

    • mkfs.ext4 (from under NixOS on a bootable USB drive),

    • mkswap.

    Here is my partition table as printed by gdisk:

    Number  Start (sector)    End (sector)  Size       Code  Name
       1              40          409639   200.0 MiB   EF00  EFI System Partition
       2          409640       104603575   49.7 GiB    AF00  Untitled
       3       104865720       261418767   74.7 GiB    AF00  Untitled
       4       261680912       287071535   12.1 GiB    8302  home
       5       287071536       307888927   9.9 GiB     8300  nixos
       7       307888928       312581774   2.2 GiB     8200  swap
    
  2. Cable Ethernet Internet connection.

  3. A USB drive formatted as FAT with MBR and labelled NIXOS_ISO, with a copy (dragged and dropped) of the content of the NixOS 15.09 64-bit ISO image (Live CD or Minimal).

    • The label of the USB drive must be NIXOS_ISO (i tried with FLASH once, it didn't work).

    • It seems that NixOS 15.09 ISO images cannot be mounted under Mac OS. If the image cannot be mounted, it is enough to extract its contents. I could extract the contents of the ISO image with Keka file archiver.

Installation

  1. Boot from the USB drive by holding down the Alt/Option key when rebooting and by selecting the USB EFI Boot. Log in as "root" (without password). Make sure the Internet connection is working. Internet connection is necessary for the installation.

  2. Execute

    swapon /dev/disk/by-label/swap
    mount /dev/disk/by-label/nixos /mnt
    mkdir /mnt/boot
    mkdir /mnt/home
    mount /dev/disk/by-label/EFI  /mnt/boot
    mount /dev/disk/by-label/home /mnt/home
    nixos-generate-config --root /mnt
    
  3. Add

    nixpkgs.config.allowUnfree = true;
    

    in the generated /mnt/etc/nixos/configuration.nix file.

  4. Execute

    nixos-install
    
  5. Reboot:

    reboot
    

Booting

(This was my experience with 14.04.)

After rebooting, the computer booted into NixOS. I rebooted again, holding this time the Alt/Option key. The boot menu showed two identically looking "EFI Boot" items. It turned out that one of them is Mac OS, and the other is NixOS. (Strange -- before the one with Mac OS was named after the Mac OS partition.) Ok.

I mounted and inspected the content of the EFI system partition out of curiosity:

§ tree /Volumes/EFI/
.
├── EFI
│   ├── APPLE
│   │   ├── EXTENSIONS
│   │   │   └── Firmware.scap
│   │   └── FIRMWARE
│   │       └── MB51_007D_03B_LOCKED.scap
│   ├── Boot
│   │   └── BOOTX64.EFI
│   ├── gummiboot
│   │   └── gummibootx64.efi
│   └── nixos
│       ├── 5683z247xmsrh4lyr2hgpxwlb9gg5wyl-linux-3.12.20-bzImage.efi
│       └── mmjxbf6vwp5mwb384yfd6c8vkhd19gx8-initrd-initrd.efi
└── loader
    ├── entries
    │   └── nixos-generation-1.conf
    └── loader.conf

Everything there but /EFI/APPLE and its content has been created by NixOS installation.

Making Mac OS default again

(This was my experience with 14.04.)

To make Mac OS default again and to make the corresponding item in the Option-key boot menu named after the Mac OS partition, it was enough to go to System Preferences... > Startup Disk under Mac OS and select the partition with Mac OS. Strangely, it required entering the admin password twice, and the partition was still not shown as selected, but otherwise it worked.

Other instructions

  • To always see gummiboot menu, it is enough to set boot.loader.gummiboot.timeout in configuration.nix.

  • To configure properly my nVidia graphics card, i ended up using the open-source nouveau driver:

    services.xserver.videoDrivers = [ "nouveau" ];
    

    I have no complaints about it. If i use the proprietary "nvidia" instead, text consoles do not work.

    Update for NixOS 16.09. I observed that on my machine with NixOS 16.09, the option services.xserver.videoDrivers is not needed in configuration.nix for everything to work well, and that in fact it noticeably degrades the graphical performance according to a few tests i did with glmark2 OpenGL benchmark. I also observed that selecting "nvidia" breaks graphical mode but leaves text consoles, contrary to what i observed with Nix OS 14.04. This all looks a bit strange to me, but this is what i observed, so i removed this option from my configuration.nix.

  • To load the applesmc module (for the sudden motion sensor, for example) it was suggested to me to add the following to configuration.nix:

    boot.kernelModules = [ "applesmc" ];
    

Remarks and observations

The only "problem" with NixOS on my MacBook that i have observed so far is that running NixOS my laptop usually gets 5-10 °C hotter than under Mac OS 10.9. This might be a usual problem for Linux on a Mac.

Links to alternative installation instructions

  • Install Linux on a MacBook Air, 17/06/2015 (Installing NixOS on a MacBook Air in a dual-boot configuration with Mac OS).

Some additional tips:

If you want to get your backlight working and prevent your laptop from spontaneously resuming while the lid is closed, you can use something like the following in your configuration.nix:

  # Enable the backlight control on rMBP 
  # Disable USB-based wakeup
  # see: https://wiki.archlinux.org/index.php/MacBookPro11,x
  powerManagement.powerUpCommands = ''
    if [[ "$(cat /sys/class/dmi/id/product_name)" == "MacBookPro11,3" ]]; then
      ${pkgs.pciutils}/bin/setpci -v -H1 -s 00:01.00 BRIDGE_CONTROL=0

      if cat /proc/acpi/wakeup | grep XHC1 | grep -q enabled; then
        echo XHC1 > /proc/acpi/wakeup
      fi
    fi
  '';

Depending on your MacBook version, you might need to tweak the above commands, so please don't blindly copy-and-paste.