Installing Debian Jessie on a Dell XPS 13 9350 via a custom Debian Installer ISO with complete hardware support

Since its initial announcement at CES back in January 2015 I've kept a close eye on the progression of the venerable Dell XPS 13 9343 Ultrabook. The 9343's evolutionary successor, the "9350", was released later that year and boasted various hardware improvements in addition to having substituted the mini-DisplayPort for a more versatile Thunderbolt 3/USB 3.1 Gen 2 port.

Intro

With my Dell Studio 1558 dying* on me in the latter end of the third year at Loughborough University I ended up getting a cheap $350 replacement in the form of a Lenovo G500s that continues to serve me well to this day. Being on the more affordable, entry-level side of the hardware component scale the G500s never really excelled in any particular aspect - nor did I expect it to at that price point!

Enter the Dell XPS 13 9350. With its countless positive reviews from numerous tech sites (ZDNet, computershopper, expertreviews, notebookcheck), bleeding edge hardware in every sense encompassing 6th generation Intel Skylake processors ("toc"), NVMe PCIe SSD support, its stunning "InfinityEdge" display, small + lightweight form factor, and a battery life that nears the 10+ hour mark when handling "real world" usage.**

My Dell XPS 13 9350 Specifications

With a focus on maximising battery life in tandem with an aversion for touch screen based Ultrabooks (fingerprints look terrible!) I decided to go with a battery conscious hardware configuration; this meant forgoing the very top end i7-6500U CPU and FQHD (3200x1800) "InfinityEdge" display. Another hardware concession that I consciously made was choosing an AHCI based M.2 SATA SSD over Dell's NVMe PCIe SSD option. I made this particular decision with the intention of eventually upgrading the M.2 SSD to a larger sized and better performing NVMe PCIe based SSD (e.g. the 512GB Samsung 950 Pro) than Dell's own offering.

  • CPU: 6th Generation Intel(R) Core(TM) i5-6200U
  • RAM: 8GB LPDDR3 1866MHz
  • SSD: 128GB M.2 Solid State Drive (AHCI)
  • Display: 13.3 inch FHD AG (1920 x 1080) InfinityEdge
  • WiFi + Bluetooth Adapter: DW1820A 2x2 802.11ac 2.4/5GHz + Bluetooth4.1 (Broadcom BCM4350)

Broadly speaking this guide covers:

  • Updating the Dell XPS 13 9350's BIOS to the latest available firmware via a FreeDOS live USB environment.

  • The creation and packaging (as a Debian binary archive) of a custom Linux 4.4 kernel that supports all of my Dell 13 9350's hardware***.

  • The configuration and compilation of a custom Debian Jessie Installer Hybrid based ISO (i.e. USB/CD-ROM agnostic) with the official debian-cd utility.
    The configuration outlines all the steps taken for adding custom packages/files to the installer ISO from the previously built custom Linux 4.4 kernel Debian binary package and the necessary firmware Debian packages/files which, in combination, result in complete hardware support for my Dell XPS 13 9350 upon installation.

  • Editing the compiled custom Debian Installer's initrd.gz midway through the debian-cd process in order to inject a script that runs at the end of the installation process. This is necessary for the Bluetooth firmware file to to be autonomously copied to the correct installation directory.

  • Booting the custom made Debian Jessie Installer via USB and outlining the nuances present when installing Debian Jessie 8.3 via the "Expert Installation" option. I've embedded an Asciinema console recording so as to succinctly illustrate these nuances.

  • Upon successful installation and subsequent boot from the Dell XPS 13 9350's internal storage I outline the steps required for scanning and connecting to an encrypted (WPA2) WiFi Access Point. (With the presumption that it provides internet access...)

  • Invoking tasksel for a menu driven, ncurses based "wizard" that assists with installing numerous packages in order to satisfy the selection of user selected high-level "Software Options" (e.g GNOME 3 desktop environment). This menu would have otherwise been present in a traditional Debian Installer that had internet access.

My main intention for creating this custom Debian Installer ISO image in addition to writing this fairly extensive guide was to:

  1. Get a better idea on how Debian Installer ISO images were put together by the Debian developers. Having recently mirrored the entire amd64 architecture for all branches of Debian I wanted to investigate the feasibility of building up-to-date (and custom) Debian installation media for my virtual environments. Being able to construct targeted Debian Installation images (i.e. branch and content specific) locally would accelerate VM deployment rate while simultaneously reduce the bandwidth consumption for the otherwise targeted Debian Installer mirror.

  2. To start my process of giving back to the Debian community and users of the Debian GNU/Linux system with a straightforward installation media that provides an "as expected" standard of functionality (i.e. full hardware support!) in addition to a minimal base installation footprint that I have become used to with Debian.

Scenarios

"I have already installed Debian - I just want all the hardware to work!"

Glad to hear you got a base Debian system operational! Take a look at the "Existing Installation" link in the Downloads section (below) for obtaining the necessary custom Linux 4.4 kernel and non free firmware packages.
Note: Select the firmware package that corresponds to your WiFi adapter (e.g. firmware-brcm80211_20160110-1_all.deb corresponds to the Broadcom BCM4350 chipset).

Once you have downloaded the Debian binary packages you can go ahead and install them as is: sudo dpkg -i *.deb
Note: The packages are able to operate on a "standalone" basis; in other words they do not depend on any other packages being installed beforehand.

Once all the Debian binary packages have been installed and you have rebooted into the custom Linux 4.4 kernel continue to follow the guide from section 9 onwards to understand how to connect to an encrypted WiFi AP via the command line.
Note: Please ensure you have updated the firmware to the latest release! See step 1 in the guide for how to update the Dell XPS 13 9350's BIOS.

"I'm not interested with how this ISO was made - I just want a straightforward Debian installation that includes all the necessary drivers!"

I hear you loud and clear. The custom Debian Jessie Installer ISO link can be found in the Downloads section (below) labelled as the "Fresh Installation" option.

Once you have downloaded the ISO image you can skip to section 8 in the guide which will walk you through the remainder of the steps required for installing a Debian Jessie 8.3 environment with complete hardware support on your shiny Dell XPS 13 9350. Additional steps, as previously mentioned, outline the commands required for connecting to an encrypted WiFi AP and installing various software setups based off the available tasksel options.

Downloads

In an effort to cater to both scenarios outlined above I have provided two separate download options. Pick one that most suits the scenario you face:

Note: md5sums are included within both the custom Debian Jessie Installer ISO and the Debian binary packages respectively.

Packages Used

bzip: 1.0.6-7+b3
binutils: 2.25-5
fakeroot: 1.20.2-1
kernel-package: 13.014+nmu1
libncurses5-dev: 5.9+20140913-1+b1
wget: 1.16-1
debian-cd: 3.1.17

1. Configure the 9350's BIOS to enable Legacy USB booting

The Dell XPS 13 9350 is no exception to the rule when it comes to the gradual assimilation of UEFI over the legacy BIOS implementation in consumer targeted hardware solutions. As Dell made the (arguably well placed) assumption that the majority of its users would use Microsoft Windows 10, and only Microsoft Windows 10, as the bare metal OS a series of UEFI configurations are necessary to permit (i.e. disable Secure Boot) and enable "Legacy" (i.e. MBR driven booting as opposed to a dedicated EFI System Partition) based booting via USB.
Note: You can skip this section if you have already installed Debian and have the most up-to-date BIOS firmware flashed already.

1. Turn the Dell XPS 13 9350 on and press the F2 button when presented with the Dell POST logo.

2. Navigate to the "Boot Sequence" category: Settings -> General -> Boot Sequence.
Change the "Boot List Option" to: legacy.
Change the ordering of the "Boot Sequence" so as the USB Storage Device is the first entry in the list.

3. Change the "SATA Operation" value to AHCI: Settings -> System Configuration -> SATA Operation: AHCI

4. Disable the "Secure Boot" feature: Settings -> Secure Boot Enable -> Secure Boot Enable: Disabled

Now we have performed the necessary UEFI configuration to provide booting from USB we can go ahead and update the BIOS (if not done already) and boot the custom Debian Jessie Installer ISO (if choosing the fresh installation option).

2. Updating the 9350's BIOS

The most recent Dell XPS 13 9350 BIOS firmware can be downloaded from the official Dell site here.
Be aware that the BIOS seems to be in active development with the current release being at build version 1.2.3 (as of 30/01/2016) despite being at 1.1.9 only just two weeks ago when I initially updated.

As always BIOS updates can fix (but sometimes introduce!) various hardware issues while simultaneously improving support for various peripherals (e.g. Dell Thunderbolt 3 docks). Consequently I would recommend checking the above Dell XPS 13 9350 BIOS firmware download page on a semi-frequent basis to ensure you are benefiting from the latest firmware enhancements/fixes.

The simplest approach for updating the BIOS is to install the downloaded BIOS firmware executable within a Microsoft Windows OS environment. However, for this guide I take a different update path that alleviates the requirement of a preexisting Microsoft Windows OS environment. Instead I utilise "FreeDOS" which makes it possible for the user to update their Dell XPS 13 9350's BIOS in the situation where they do not have access to the Microsoft Windows OS environment.
Note: You need to ensure that your Dell XPS 13 9350 can boot from USB. See the previous section in the guide for doing this.

5. Download a compressed, minimal version of FreeDOS that supports being booted from a USB:
wget http://ftp.chtaube.eu/pub/FreeDOS/bootable-usb/FreeDOS-1.1-memstick-2-256M.img.bz2 -O ~/FreeDOS-1.1-memstick-2-256M.img.bz2

6. Extract the "Bzipped" FreeDOS image: bunzip --decompress ~/FreeDOS-1.1-memstick-2-256M.img.bz2

7. Write the FreeDOS image to a USB mass storage device: sudo dd if=/mnt/storage/Iso/Freedos/FreeDOS-1.1-memstick-2-256M.img bs=1M of=/dev/sdX
Take care ensuring that the sdX SCSI device node corresponds to your targeted USB mass storage device.

8. Instruct the kernel to "rescan" the USB mass storage device so we can identify the single FreeDOS FAT32 based OS partition:
sudo partprobe /dev/sdX
-- OR --
echo 1 | sudo tee /sys/block/sdX/device/rescan

9. Create a dedicated mount point for the FreeDOS FAT32 based OS partition so we can copy the latest Dell XPS 13 9350 BIOS firmware executable (.exe file) onto it.
sudo mkdir /mnt/freedos
sudo mount /dev/sdX1 /mnt/freedos

10. Download the latest Dell XPS 13 9350 BIOS firmware and save it under the /mnt/freedos/fdos directory. As this link changes often you will need to navigate to the Dell XPS 13 9350 downloads page and copy the most recent download link for the BIOS firmware. In other words do not try to copy and paste the below command, it is simply to serve as a rough example of the sort of structure to expect:
sudo wget http://downloads.dell.com/PATH/TO/XPS_9350_1.X.Y.exe -O /mnt/freedos/fdos/XPS_9350_1.X.Y.exe
Note: We need to use sudo here as the FAT32 based mount point does not permit traditional UNIX privileges and hence only root can write (unless, of course, further configuration was performed) to the filesystem.

11. Unmount the USB stick and plug it in to either of the two provided USB 3.0 ports exposed by the Dell XPS 13 9350. Ensure that the Dell XPS 13 9350 is turned off at this stage.

12. Power up the Dell XPS 13 9350 and press the Enter key when presented with the initial FreeDOS menu to continue booting into the FreeDOS OS.

13. When presented with the menu for booting various permutations of the FreeDOS OS select the 4th option: Load FreeDOS without drivers
The reason we select this option is because the following error: "JemmEx: exception 0D occurred at CS:EIP=E400:000099C, ... [CS:IP]=67 66 26 8B 07 80 3E 02" arises when attempting to run the BIOS firmware executable; ultimately prevents the BIOS firmware update from installing correctly.

14. Once presented with the FreeDOS shell prompt navigate to the fdos directory and invoke the BIOS update executable (by hitting the Enter key):
C:>cd fdos\
C:\FDOS>xps_93~1.exe
The final command in this step appears odd and I believe its related to the manner in which particular file names are handled by the FreeDOS OS. Anyways press the Tab key after typing 'xps' to automatically populate the correct file name.

15. Once the ncurses styled menu appears giving a brief oversight into the operations the BIOS firmware update will do in addition to the warnings related to power failure during the flashing process we can go ahead and commence the update by pressing the 'y' key.
While the flashing process does not take longer than 5 minutes it is always wise to connect the laptop to a live power outlet to protect against power failures arising from an empty battery!

3. Determining and obtaining firmware packages

Beside employing the traditional lscpi -vv command to get an idea of the hardware neatly arranged inside my Dell XPS 13 9350 I scoured a variety of Linux oriented websites in an effort to identify which kernel drivers were required.
I've decided to include this section to provide those interested in further configuration and understanding of the kernel drivers employed by Linux for powering their Dell XPS 13 9350.

  • Arch Linux Wiki: Outlined the drivers that were tested as functional by the Arch Linux community members. Once I had ascertained the name of kernel drivers that worked I set about "Googling" which kernel configuration option they corresponded to.

  • Gentoo Linux Wiki: Despite targeting the Dell XPS 13 9350's predecessor, the 9343, I found that for the certain hardware components had persisted between the incremental upgrade (e.g. USB controller). From the documentation I was able to get a quick start on the location of the kernel configuration options within the ncurses driven make menuconfig kernel configuration menu.

  • Debian Package explorer: Some hardware required a firmware counterpart in addition to their respective kernel configuration. From here I was able to ensure that the correct firmware file was procured between (e.g. Broadcom Wifi, Intel Skylake microcode, etc.) the various revisions (based on the branch of Debian) of the firmware based Debian binary package.
    Note: All firmware based Debian binary packages have been procured from the Sid branch of Debian. Jessie and Stretch versions of the Firmware package did not include the required firmware files.

4. Compiling a custom 4.4 Linux Kernel

With kernel compilations on my server (Octeron) being performed on a regular basis I have become very familiar with the preparation, compilation, and installation process of building custom kernels. I use a distribution agnostic process for compiling and installing kernels which results in a slight management overhead from having to maintain a handful of custom kernels.

To increase the custom kernel's portability and ease of installation within other Debian GNU/Linux systems I took the decision to adjust my process, in particular the installation phase, so as to produce a Debian binary archive (.deb) at the end of the overall compilation process. This Debian binary archive could then be easily maintained by the end user's APT environment as it would appear and behave like a typical Debian package.
So as to remain as identical as possible to the authentic Debian distributed kernel's, I took the kernel configuration file (.config) from the Debian Experimental repository and only appended the driver options that were otherwise missing.
For brevity I have omitted the steps necessary for procuring this configuration file but will happily add them to this section in the guide if requested.

The Broadcom BCM4350 chipset found in my Dell XPS 13 9350 was recently included in the mainline Linux 4.4 kernel release under the guise of this patch. Unfortunately this driver requires a closed source firmware binary blob to operate correctly on the Dell XPS 13 9350. More details regarding the firmware required and the package it is contained within is explained in step 3 of this guide.

The steps necessary for preparing, compiling, and packaging a custom Linux 4.4 kernel and corresponding kernel headers is as follows. I used the Gentoo wiki for the Dell XPS 13 9343 kernel configuration (here) as a rough guideline for ensuring that I had selected the correct CONFIG_* options during preparation.

16. Install the packages necessary for compiling a Linux kernel and packaging it in a Debian binary archive format:
sudo apt-get install binutils fakeroot kernel-package libncursesdev-5 wget

17. Create a dedicated build directory for the vanilla Linux 4.4 kernel and navigate to it:
mkdir ~/linux-source-4.4
cd ~/linux-source-4.4

18. Download the compressed Linux 4.4 kernel source tarball:
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.tar.xz

19. Extract the compressed tarball and navigate into the resulting linux-4.4 directory:
tar -xJf linux-4.4.tar.xz
cd linux-4.4

20. Copy the existing kernel configuration file (.config) stored within the Debian Experimental package linux-source-4.4_4.4~rc8-1~exp1_all.deb to the current directory.
cp /path/to/extracted/experimental/linux-source/.config ~/linux-source-4.4/linux-4.4/.config

21. Configure the kernel to include all necessary drivers for my Dell XPS 13 9350's hardware configuration:
make menuconfig

22. Compile the custom kernel and corresponding kernel headers with the Debian utilities for ultimately producing two easily installed Debian binary archives. I recommend utilise all CPU cores available for reducing the total compilation time required.
export CONCURRENCY_LEVEL=$NUM_OF_CORES+1
sudo fakeroot make-kpkg --initrd --revision=9350 kernel_image kernel_headers
Make sure to substitute $NUM_OF_CORES+1 to the number of available CPU cores + 1 on your host.
Once completed the custom Linux 4.4 kernel and corresponding headers can be found in their respective Debian binary package in the build directory's parent directory: ~/linux-{image,headers}-4.4.0_9350_amd64.deb
Note: Approximately 10GiB of free space was required for this compilation.

At this stage we have managed to compile and package a custom Linux 4.4 kernel and corresponding kernel headers that supports all the hardware found in my Dell XPS 13 9350.
By including the kernel headers as part of the custom Debian Installer ISO it has allowed my custom kernel to accept future kernel modules (if desired) to be compiled against it and managed via DKMS.

For those interested in the custom 4.4 kernel configuration file (.config) used I have uploaded it here. As stated previously: I only made minimal alterations (mainly additions) in an effort to follow the Debian Experimental's Linux image as closely as possible.
Nevertheless, I intend to further reduce this particular custom kernel's hardware (CPU, RAM, and SSD) footprint by removing all unnecessary drivers for hardware the Dell XPS 13 9350 does not have. I'll update this post once I have created a streamlined custom kernel targeting the hardware present in my Dell XPS 13 9350. I shall endeavor to include the drivers necessary for other Dell XPS 13 9350 configurations but cannot promise they will work!

5. Modifying the custom Linux 4.4 kernel's "control" file

One of the trickiest parts of configuring a custom Debian Jessie installer ISO was understanding how the Debian Installer ascertained what was (and wasn't) an acceptable Linux kernel package.
After countless hours exploring scripts and reading aborted Debian Installation logs I found that the Debian Jessie Installer initrd.gz (examined in greater depth later in this guide) contained the script /usr/lib/base-installer/kernel.sh which, after loading installer components from the installation media at run time, would check the packages with their section field (as denoted in the Packages.gz file) being listed as only "kernel" to see if they matched the following criteria:

# /usr/lib/base-installer/kernel.sh
...
arch_check_usable_kernel () {  
    case "$1" in
       *-dbg)
           return 1
           ;;
        *-amd64 | *-amd64-*)
           # Allow any other hyphenated suffix
           return 0
           ;;
        *)
           return 1
           ;;
    esac
}
...

If the kernel package's name as listed in the kernel package's "control" file did not match the kernel.sh's regex filter than that particular kernel would not be listed in the kernel selection menu as part of the installation process!

In my best efforts to avoid turning this already long blog post into a sizeable essay I have decided to omit a description of the contents of Debian binary packages. For those interested I would strongly recommend reading chapter 5 "Packaging System: Tools and Fundamental Principles" of the excellent Debian Administrator's Handbook (here).

23. Create and navigate into a dedicated directory for extracting the newly packaged custom Linux 4.4 kernel:
mkdir ~/custom-kernel
cd ~/custom-kernel

24. Move the custom Linux 4.4 kernel Debian binary package into the ~/custom-kernel directory:
mv ~/linux-image-4.4.0_9350_amd64.deb ~/custom-kernel

25. Extract the custom Linux 4.4 kernel Debian binary package from its archive:
ar r linux-image-4.4.0_9350_amd64.deb

26. Create a dedicated directory for the meta-data based "control" files and navigate into it:
mkdir ~/custom-kernel/control
cd ~/custom-kernel/control

27. Extract the control.tar.gz so we can get access to the custom Linux 4.4 kernel Debian binary package's "control" file:
gunzip --stdout ../control.tar.gz | tar -xf -

28. With your favourite text editor open the newly extracted control file and append "-amd64" to the value set in the Package field:
Package: linux-image-4.4.0-amd64

29. Construct a new compressed (gzipped) tarball control.tar.gz from all the files present in the current directory:
tar -c * | gzip --stdout --best > ../control.tar/gz

30. Navigate to the parent directory containing the newly compressed control.tar.gz tarball and other untouched Debian package components (i.e. data.tar.xz, debian-binary):
cd ~/custom-kernel

31. Repackage the custom Linux 4.4 kernel Debian binary archive:
ar r linux-image-4.4.0_9350_amd64.deb debian-binary control.tar.gz data.tar.xz
Note: The order here (i.e. debian-binary first) of files to be included in the archive is critical!

32. Move the altered custom Linux 4.4 Debian binary package to the directory designated in the previous section:
mv ~/custom-kernel/linux-image-4.4.0_9350_amd64.deb /path/to/my/custom/debs

I found that the custom Linux 4.4 kernel headers' "control" file did not list the originally named linux-image-4.4.0 package as a Dependency so would not need to be altered to correctly reference the renamed custom Linux 4.4 kernel package.
For consistency purposes I decided to suffix the kernel headers' "control" file Package name with "-amd64". I followed an almost identical process to the above steps for making this change and have consequently omitted these repetitive steps here.

6. Configuring and compiling a custom Debian Jessie Installer ISO

The debian-cd package is a collection of scripts used by the Debian CD team for the production of the official and daily/weekly Debian Installer CD/DVD images. In addition to the package being available in the "main" repository (here) for the latest Git development branch can be cloned (here).

Despite having read the debian-cd's supplied README on several occasions I faced a variety of undocumented hurdles when attempting to include my own set of custom packages in my custom Debian Jessie installer ISO. Moreover I encountered further challenges when trying to include my own custom scripts for automating the copying of the Bluetooth firmware file.
I've outlined these various difficulties throughout this section as well as the following section in the hope they assist others who wish to alter the Debian Installer image in a similar fashion.

33. Install the debian-cd package required for constructing a Debian Jessie Installer ISO image in addition to the dpkg-dev package which provides the dpkg-scanpackages helper utility for generating Package lists:
sudo apt-get install debian-cd dpkg-dev

34. Create a dedicated directory for copying the debian-cd package contents (scripts, configuration files, READMEs, etc) to:
mkdir ~/debian-cd
cp -R /usr/share/debian-cd ~/debian-cd

35. Alter the ownership of the copied debian-cd files to that of the current user:
sudo chown -R grindon:grindon ~/debian-cd

36. Create the required debian-cd dedicated build directories on the same partition as that of the locally stored Debian mirror. In addition to this create a dedicated "custom" directory that will store our custom Debian packages:
mkdir -p /mnt/archive/dell/{tmp,apt-tmp,images,custom}

37. Create the required directory structure for correctly adding custom packages during the Debian Jessie Installer ISO creation:
mkdir -p /mnt/archive/dell/custom/dists/jessie/local/binary-amd64
Where "jessie" and "binary-amd64" have been substituted in from their variable counterpart $CODENAME and $ARCH respectively for this particular custom Debian Jessie Installer ISO image.

38. Copy the custom Linux 4.4 kernel and headers as well as all the firmware packages into the directory created in the previous step:
cp /path/to/my/custom/debs/* /mnt/archive/dell/custom/dists/jessie/local/binary-amd64
I have listed these custom and firmware based packages in the previous section of this guide.

39. Generate a "package list" of the custom and firmware based packages in a format that can be consumed by the debian-cd script suite:
dpkg-scanpackages /mnt/archive/dell/custom | gzip --stdout --best > /mnt/archive/dell/custom/dists/jessie/local/binary-amd64/Packages.gz
By invoking the dpkg-scanpackages utility at the /mnt/archive/dell/custom/ directory level we ensure that each package's path value is of a valid structure that ensures a correct lookup when the Debian Installer attempts to install the package. E.g. /dists/jessie/local/binary-amd64/firmware-brcm80211_20160110-1_all.deb

40. Navigate to the ~/debian-cd created in step 34:
cd ~/debian-cd

41. With your favourite text editor edit the CONF.sh file and adjust the following values:

export BASEDIR=`pwd`  
export CDNAME=debian  
export CODENAME=jessie  
# Important to use the corresponding distributions d-i otherwise kernel ABI breakages!
# 'current' just points to the latest d-i build (vmlinuz & intird.gz pair) available for Jessie
export DI_WWW_HOME=http://10.0.1.254/debian/dists/jessie/main/installer-amd64/current/images  
export DEBVERSION="8.3.0"

export MIRROR=/mnt/archive/mirrors/debian  
export TDIR=/mnt/archive/dell/temp  
export OUT=/mnt/archive/dell/images  
export APTTMP=/mnt/archive/dell/apt-temp

# Firmware packages don't get added otherwise...
export FORCE_FIRMWARE=1  
export LOCAL=1  
export LOCALDEBS=/mnt/archive/dell/custom

export amd64_MKISOFS="xorriso"  
export amd64_MKISOFS_OPTS="-as mkisofs -r -checksum_algorithm_iso md5,sha1"

export ARCHIVE_KEYRING_PACKAGE=debian-archive-keyring  
export ARCHIVE_KEYRING_FILE=usr/share/keyrings/debian-archive-keyring.gpg  
export DEBOOTSTRAP_OPTS="--keyring $TDIR/archive-keyring/$ARCHIVE_KEYRING_FILE"  
export ISOLINUX=1

export DISKTYPE=NETINST  
export IMAGESUMS=1

# Path to file listing additional main & custom packages for inclusion
export BASE_INCLUDE="$BASEDIR"/data/$CODENAME/base_include

export INSTALLER_CD=2  
export TASK=debian-installer+kernel  
export MAXCDS=1

# Saving disk space
export OMIT_MANUAL=1  
export OMIT_RELEASE_NOTES=1  

For brevity I have omitted an explanation of the configuration options listed above. A brief explanation for each option can be found in the debian-cd's CONF.sh file.

42. With your favorite text editor append the necessary packages (firmware, custom, and "main") to be included in the custom Debian Jessie Installer ISO image to the ~/debian-cd/data/jessie/base_include file:

wpasupplicant  
iw  
wireless-tools  
tasksel  
firmware-brcm80211  
firmware-iwlwifi  
firmware-misc-nonfree  

Note: The omission of both the linux-image-4.4.0-amd64 and linux-headers-4.4.0-amd64 packages is on purpose at this stage. From my own testing I found that including the custom Linux 4.4 kernel as part of the ~/debian-cd/data/jessie/base_include file seems to confuse the Debian Installer and results in a failed installation.

44. Ensure you are in the ~/debian-cd directory and source the modified CONF.sh configuration file into the shell's current session:
source CONF.sh

45. Commence the first step of the debian-cd process. While not necessary for the initial build I find it alleviates any potential headaches early in the bootstrapping process:
make distclean

46. Commence the second step of the debian-cd process. At this stage the debian-cd utility "initializes the temporary directory used for the build":
make status

47. We now slightly digress from the debian-cd process so as to edit the TASK file "debian-installer+kernel" in the designated TDIR build directory /mnt/archive/dell/temp/ to replace the stock kernel with our custom Linux 4.4 kernel.
With your favourite text editor open the /mnt/archive/dell/tmp/jessie/tasks/debian-installer+kernel task file and substitute the stock Linux kernel image within the amd64 architecture ifdef block for the name of the custom Linux 4.4 kernel package name:

...
#ifdef ARCH_amd64
initramfs-tools  
busybox  
grub-legacy  
grub-pc  
grub-efi  
grub-efi-amd64  
grub-efi-amd64-bin  
laptop-detect  
lilo  
linux-image-4.4.0-amd64  
linux-headers-4.4.0-amd64  
#endif
...

48. Commence the third step of the debian-cd process. At this point we decide what packages we want (as dictated by the TASK variable referencing a corresponding plain text file in ~/debian-cd/tasks/jessie/ that lists packages) to place on the ISO in addition to how many ISO images we want to create. Typically you would pass the TASK and COMPLETE values as flags to the make invocation phase however I included them within the CONF.sh in an effort to simplify the chainloading commands:
make packagelists

49. Commence the fourth and penultimate step of the debian-cd process. This phase consumes the list of packages set by the desired TASK and performs the necessary operations for resolving all package dependencies where required. A plethora of other Hybrid ISO oriented preparation steps are performed at this stage and are documented in the ~/debian-cd/README file:
make image trees

50. With the contents of the custom Debian Jessie Installer ISO being practically completed at this stage, we can again interrupt the debian-cd process and include my Dell XPS 13 9350's Bluetooth firmware driver.
Unfortunately the Bluetooth firmware file is not part of an existing Debian binary package like other firmware files and consequently will need to be manually included into the Debian Jessie Installer ISO:
cp /path/to/firmware/BCM-0a5c-6412.hcd /mnt/archive/dell/tmp/jessie/CD1/firmware
chown grindon:grindon /mnt/archive/dell/tmp/jessie/CD1/firmware/BCM-0a5c-6412.hcd
chmod 644 /mnt/archive/dell/tmp/jessie/CD1/firmware/BCM-0a5c-6412.hcd

This Bluetooth firmware file is intended to be copied autonomously by the Debian Installer to the target installation's directory: /target/lib/firmware/brcm/BCM-0a5c-6412.hcd so as to be loaded automatically at boot. Adjusting the ownership and permissions ensures the firmware is correctly

For brevity I have omitted the process of converting the Microsoft Windows Bluetooth driver (for the BCM4350 Bluetooth 4.1 + WiFi adapter) to a Linux compatible driver via the hex2hcd utility. For those interested the Arch Linux wiki outlines the steps and utilities involved for performing this conversion (here).

7. Adding a custom script to the Debian Jessie Installer's initrd.gz

The manner in which the ISO is booted (UEFI or MBR) will determine which bootloader (Syslinux or GRUB2) is loaded by the Debian Installer (source). In addition to this other aspects of the installer behave differently (i.e partition configuration, GRUB installation) to ensure an operational installation of a GNU/Linux Debian system.

All scripts used by the Debian Jessie Installer are located within the initrd.gz for both the GTK (Graphical) and ncurses (Expert/Rescue/Automated) boot options. For automating the copying of the Bluetooth firmware file BCM-0a5c-6412.hcd we need to include a custom script ("Hook") that will run at the end of the installation. To achieve this we must decompress and extract the CPIO based archive (initrd.gz), insert the custom script in the correct directory, generate a new CPIO archive, compress (gzip) the new CPIO archive, and finally replace the Expert Installation option's initrd.gz.
For those interested, the official documentation for the Debian Installer processes/components within the initrd.gz can be found here.

Identifying which kernel and initrd pair the Expert Install option uses when booting via UEFI can be identified by examining the /mnt/archive/dell/tmp/jessie/CD1/boot/grub/grub.cfg configuration file:

...
menuentry '... Expert install' {  
    set background_color=black
    linux    /install.amd/vmlinuz priority=low vga=788 --- 
    initrd   /install.amd/initrd.gz
}
...

51. Create a dedicated directory for the Expert Installation option's initrd.gz and copy the initrd.gz file to it:
mkdir ~/custom-initrd
cp /mnt/archive/dell/tmp/jessie/CD1/install.amd/initrd.gz ~/custom-initrd

52. Extract the gzipped CPIO archive:
gunzip ~/custom-initrd/initrd.gz

53. Create another directory, "extracted", that will store the contents of the extracted CPIO archive and navigate into it:
mkdir ~/custom-initrd/extracted
cd ~/custom-initrd/extracted

54. Extract the CPIO archive within the fakeroot utility wrapper required to isolate the mknod syscalls made by extracting the CPIO archive:
fakeroot cpio --make-directories --extract < ../initrd

55. With your favourite text editor create the custom script for installing the Bluetooth firmware file at ~/custom-initrd/extracted/usr/lib/finish-install.d/14bcm4350-bluetooth:

 #! /bin/sh -e

 # Copying the BCM4350 Bluetooth hcd firmware file to the install target
cp /cdrom/firmware/BCM-0a5c-6412.hcd /target/lib/firmware/brcm/BCM-0a5c-6412.hcd  

56. Ensure that the 14bcm4350-bluetooth script has executable permissions:
chmod 755 ~/custom-initrd/extracted/usr/lib/finish-install.d/14bcm4350-bluetooth

57. Regenerate the CPIO archive ensuring to use the newc format for the archive:
find ~/custom-initd/extracted | cpio --create --format='newc' > ~/custom-initrd/initrd

58. Compress (gzip) the new initrd CPIO archive and replace it with the original one located in the previously built ISO contents:
gzip --stdout --best ~/custom-initrd/initrd > /mnt/archive/dell/tmp/jessie/CD1/install.amd/initrd.gz

59. Regenerate the md5sum hashes for all the Debian Jessie Installer files as we have now completed all of our editions:
find /mnt/archive/dell/tmp/jessie/CD1/ -type f -exec md5sum {} \; > /mnt/archive/dell/tmp/jessie/CD1/md5sum.txt

60. Navigate back to the ~/debian-cd and commence the final stage of the debian-cd process:
cd ~/debian-cd
make images

8. Writing the Hybrid ISO to USB, booting via UEFI, and installing the custom Debian 8.3 Jessie base system

The resulting custom Debian Jessie Installer Hybrid ISO image totals in at 228 MiB in size. Therefore any USB mass storage device that is 256 MB or bigger in capacity will be able to hold the ISO image.
Note: Ensure you backup any data from your chosen USB mass storage device as the following operations will wipe any existing partition tables and partition structures.

61. Write the Hybrid ISO image to the targeted USB mass storage device with the dd utility:
sudo dd if=/mnt/archive/dell/images/debian-8.3.0-amd64-NETINST-1.iso/ bs=1M of=/dev/sdX
Where "X" is the letter of the targeted SCSI based USB mass storage device. Make sure you double check this letter!

62. Turn the Dell XPS 13 9350 on and press the F2 button when presented with the Dell POST logo.

63. Navigate to the "Boot Sequence" category: Settings -> General -> Boot Sequence.
Change the "Boot List Option" to: UEFI.

64. Plug the targeted USB mass storage device now loaded with the custom Debian Jessie Installer ISO into your Dell XPS 13 9350. Once presented with the Syslinux boot menu select the Expert Install option located under Advanced boot options section.
Note: Do not choose the Graphic Installation option as this does not utilise the custom initrd.gz I altered for autonomously copying the Bluetooth firmware to the target installation directory.

65. To avoid having to outline every installation step that diverts from a traditional Debian installation process I've embedded an Asciinema recording below of me performing the installation steps from within a UEFI enabled KVM VM.
Note: if you cannot see the embedded player below please follow this direct link: https://asciinema.org/a/c4gm89ivws4pbymzdsw8rkg7n

  • I enabled the Debian backports to ensure software such as Xorg included the required up-to-date Intel graphical drivers for a windowed environment.

  • Apologies for the slow installation! Feel free to skip the base installation phase. The VM wasn't provisioned much resources as well as being installed on the same disk the ISO was being read from...

66. Upon restart press the F2 button when presented with the Dell POST logo. Once you have entered the BIOS configuration screen ensure that a UEFI entry has been made for 'debian' and is selected as the top option. If the entry does not exist the installation has not prepared GRUB correctly or the custom Debian Jessie Installer was booted via MBR as opposed to UEFI.

9. Post-installation configurations

If upon rebooting you have had the GRUB2 bootloader appear correctly after POST, had the custom Linux 4.4.0 kernel boot without issue, and finally been presented with a blinking login shell you can give yourself a high five as the core Debian Jessie 8.3 system has now been correctly installed - well done!

The final following steps outline, as mentioned previously, the steps for connecting to an encrypted (WPA2 Personal) wireless access point and running the tasksel utility to simplify installing a particular desktop environment (if desired!).

67. Login to the Dell XPS 13 9350's Debian Jessie 8.3 environment as the root user with the password set in the installation phase.

68. Enable the Dell XPS 13 9350's WiFi interface wlan0:
sudo ip link set dev wlan0 up

69. Scan for your targeted Encrypted Access Point SSID:
sudo iw wlan0 scan | grep SSID

70. Generate a WPA PSK from an ASCII passphrase for the targeted SSID:
wpa_passphrase "$SSID_NAME" > /home/$USER_NAME/ssid_psk.key
Type the password/passphrase on the empty new line when prompted. Once completed hit [enter] and the passphrase will be committed to the file in its PSK hash format.

71. Alter permissions of the newly generated ssid_psk.key file:
chmod 600 /home/$USER_NAME/ssid_psk.key

72. Connect to the WPA PSK encrypted access point ensuring to use the ssid_psk.key key:
wpa_supplicant -B -D wext -c /home/$USER_NAME/ssid_psk.key -i wlan0

73. Confirm that their is a "link level" connection between the Dell XPS 13 9350 and the targeted encrypted wireless access point:
iw wlan0 link
Example Result:

Connected to 01:23:45:67:89:0A (on wlan0)  
        SSID: Asus RT-N56U 5Ghz
        freq: 5180
        RX: 342 bytes (2 packets)
        TX: 800 bytes (8 packets)
        signal: -45dBm
        tx bitrate: 24.0MBit/s

        bss flags:
        dtim period:    1
        beacon int:     100

74. Obtain an IP address from the encrypted wireless access point's internal DHCP server:
dhclient -v wlan0
This operation will often set the Dell XPS 13 9350's DNS settings. These can be viewed from the dynamically generated /etc/resolv.conf file.

75. With either the vi or nano preinstalled text editor alter the /etc/apt/sources.list file. Ensure that you uncomment the Debian Jessie-{Update,Backport} repository URLs, append the 'contrib' option to both repositories, and create a new entry that corresponds to the base directory for the "Jessie" packages:
deb http://ftp.debian.org/debian/ jessie main non-free contrib
deb http://ftp.debian.org/debian/ jessie-updates main non-free contrib
deb http://ftp.debian.org/debian/ jessie-backports main non-free contrib

76. Update the local APT package cache to acknowledge these repository additions:
apt-get update

77. Run the tasksel utility and select the desktop environment you desire:
tasksel --new-install

Final Words

As indicated previously, I am planning to compile a minimal custom Linux kernel that would provide support for all hardware configurations of the Dell XPS 13 9350. As I have done with the custom Linux 4.4 kernel compiled in this guide I will generate the corresponding Debian binary archive for both the kernel and its respective headers to permit the compilation of additional kernel modules.
Once I have tested it on my Dell XPS 13 9350 i'll upload it to a shared directory on my Google Drive account and post the link on this post.

Having now painlessly installed a minimal Debian environment with complete hardware support my next "adventure" will be to investigate the numerous power saving adjustments that can be made in order to maximise battery life.

* Its still lives to this day as a headless Debian Jessie server but the GPU gives out when attempting to run an X11 environment. Given that Octeron handles all my virtualisation requirements the Dell Studio 1558 operates as an overpowered DNS server - I'd feel sorry for it had it not died in the middle of my writing my BSci dissertation...

** After applying all known power configurations options!

*** I have included NVMe PCIe kernel modules in addition to the drivers for the Intel WiFi but as I have not tested it I cannot confirm its effectiveness - feedback is welcome!