Install Debian on Seagate Nas 2bays

This guide explain how you can install Debian on Seagate Nas 2bays without using serial connector or voiding warranty.
Process can be easily changed to work on Seagate Nas 4 bays.
Goal is to generate a Debian image compatible with Marvell Armada 370 CPU (armhf) and to fake original firmware disk layout to allow (Seagate Nas OS) original U-boot bootloader to boot a Debian system.

Requirements

  • A Debian 8 (jessie) system
  • A blank HDD

The Easy way

Easiest way is to use an already prepared image and to flash it on HDD.
Use following link : Download Debian image for Seagate Nas 2 Bays

For Windows OS :

For Linux :
Image flash can be done using “dd” command as following

xzcat image.img.xz | dd of=/dev/sdx

Now you can insert HDD in your Seagate Nas. After 1 minute, it will ask for an IP to your DHCP server. You can connect to it using SSH.

  • Login is root
  • Password is root

The Detailed way

Step 0 : Get scripts

Use following link : Download scripts

Decompress archive using unxz
Now run scripts in following order with root rights

  1. Prepare host system : preparehost.sh
  2. Generate rootfs : roofsgen.sh
  3. Compile Kernel : kernelgen.sh
  4. Generate HDD Image : makeimg.sh

Good luck ;-)

Step 1 : Prepare host system

Install packages to generate Debian image

Following packages will be required to generate the final image :

  • multistrap : generates debian rootfs
  • qemu : CPU emulator to perform Debian package configuration on x86 host.
  • kpartx : used to generate .img file which will be flashed on HDD
aptitude -y install multistrap qemu qemu-user-static binfmt-support dpkg-cross debconf-utils curl kernel-package kernel-wedge libncurses5-dev u-boot-tools crossbuild-essential-armhf archivemount kpartx

Install Linux Kernel Source

# Get Kernel
aptitude -y install linux-source-3.16:armhf
# Unzip kernel
tar -xvf /usr/src/linux-source-3.16.tar.xz -C /usr/src/

Install Armhf cross toolchain

Armhf cross toolchain is required to compile a kernel which can run on Seagate Nas platform.
It is available on embedian.org repository

# Add embedian for Crosstoolchain
echo "deb http://emdebian.org/tools/debian/ jessie main" > /etc/apt/sources.list.d/crosstools.list 
curl http://emdebian.org/tools/debian/emdebian-toolchain-archive.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install crossbuild-essential-armhf

Define shell variables

In following scripts, I use following shell variables to make the life easier. You can customize it depending on your system version or target.

export BASEDIR=/home/myuser/debiandart #
export ROOTFS=${BASEDIR}/rootfs # Where rootfs will be generated
export MULTISTRAP=${BASEDIR}/multistrap # Contains multistrap.conf file
export FILESTOADD=${BASEDIR}/filestoadd # Contains customized files to be added to rootfs
export DTSDIR=${BASEDIR}/dts # DTS script directory
export DTSFILE=armada-370-seagate-dart2 # Name of DTS File
export DTBRENAME=armada-370-n090201 # Name of DTB file to be compatible with Seagate NasOS
export LINUXSRCDIR=/usr/src/linux-source-3.16 # Kernel source directory
export KERNELVERSION=3.16.7-ckt7 # Kernel version
export IMGFILE=${BASEDIR}/image.img # Name of image file
export MNTDIR=${BASEDIR}/mnt #Temporary directory to mount our image file
export NVDATADIR=${BASEDIR}/nvdata # Contains NVData for Uboot

Step 2 : Generate Rootfs

To generate Debian Rootfs we will use multistrap tool. It allows to create a Debian Rootfs with armhf architecture.
I selected minimal amount of packages to allow network, dhcp and apt to work correctly.

Content of multistrap.conf :

[General]
bootstrap=Debian Net Utils
aptsources=Debian
arch=armhf
directory=./rootfs/
retainsources=./sources/
unpack=true

[Debian]
packages=aptitude apt kmod lsof perl 
source=http://debian.mirrors.ovh.net/debian/
keyring=debian-archive-keyring
suite=jessie
components=main contrib non-free

[Net]
packages=netbase net-tools ethtool udev iproute iputils-ping ifupdown isc-dhcp-client ssh
suite=jessie
components=main contrib non-free

[Utils]
packages=locales adduser nano less wget dialog git initramfs-tools
suite=jessie
components=main contrib non-free

Now it is time to run multistrap which will generate rootfs.

#Multistrap Debian rootfs
multistrap -f ${MULTISTRAP}/multistrap.conf

Then to perform debian configuration on x86 host platform, I use Qemu. It simply needs to be copied in our

#Copy QEMU for Armel architecure
cp /usr/bin/qemu-arm-static ${ROOTFS}/usr/bin

Dash shell needs to be configured first, then all other packages can be configured through dpkg command.

mount -o bind /dev/ ${ROOTFS}/dev/
 
export DEBIAN_FRONTEND=noninterative
export DEBCONF_NONINTERACTIVE_SEEN=true
export LC_ALL=C 
export LANGUAGE=C 
export LANG=C 
 
chroot ${ROOTFS} /var/lib/dpkg/info/dash.preinst install
chroot ${ROOTFS} dpkg --configure -a
 
mount -t proc proc ${ROOTFS}/proc
 
chroot ${ROOTFS} dpkg --configure -a

It is now time to do some configuration to be able to boot on final platform.
In scripts, I simply copy filestoadd directory inside rootfs to apply all required configuration

Configure FSTAB

Due to U-boot bootloader constraints, we can only boot on ext2 partition #4. In this example, I used it as “/” We also neeed to define where is swap partition.

/dev/sda4	 /               ext2    errors=remount-ro 0       1
/dev/sda5	 none            swap    sw              0       0

Set hostname

This is done inside /etc/hostname in my example it is :

debian

Reset Nvdata script

Original Seagate U-boot has a failsafe mode. After 5 interrupted or failed boot, it directly boot on a “rescue system” located in Nand flash. To detect number of boot attempts, U-boot reads data in HDD partition #3.
To bypass this, I added a startup script which resets number of boot attempts at each system boot. This is done by erasing ubootenv file by a blank one called ubootenv-zero.

Script is located in /etc/init.d/nvdatareset

### BEGIN INIT INFO
# Provides:          nvdatareset
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: U-boot nvdata reset
# Description:       reset boot_count to allow Debian system to start
### END INIT INFO
 
case "$1" in
  start)
    echo "Resetting U-boot nvdata "
 
    mkdir /mnt/nvdata    
    mount /dev/sda3 /mnt/nvdata
    rm /mnt/nvdata/ubootenv
    cp /mnt/nvdata/ubootenv-zero /mnt/nvdata/ubootenv
    umount /mnt/nvdata
 
    ;;
  *)
    echo "Usage: /etc/init.d/nvdatareset {start}"
    exit 1
    ;;
esac
 
exit 0

To make this script executed by systemD at each boot, you need to run this command :

#Adding Script to reset boot flag
chroot ./rootfs update-rc.d nvdatareset defaults  

Configure DHCP for network interface

Goal is to allow our future Debian Nas to automatically get an IP address via DHCP server.
Configuration is located inside /network/interfaces

auto lo
iface lo inet loopback

auto eth0
allow-hotplug eth0
iface eth0 inet dhcp

Define root password

Edit /etc/shadow file and update it with a know password.
Following examples is for root password defined as “root”

root:$6$YraPn.6h$5duBUDoPrBxMMSVT2BZy9kK8PLuBw2u/Yr2M10sCkGZDjLhEQNzWF53o.SQVnUuAJU3siCs.CniJ0tVjjDheU0:16589:0:99999:7:::

Allow root login for SSH

Even this setting is not the most secure, it will help to do first login on our Debian system.
Edit /etc/ssh/sshd_config and add :

PermitRootLogin yes 

Step 3 : Compile kernel, DTB and patch initramfs

We now need to compile kernel and to generate associated DTB for our target. We will also patch debian initramfs because Seagate U-boot uses BOOT bootargs and this makes original Debian initramfs to crash during boot. Patch only consist to ignore BOOT bootarg value.

Original Seagate Uboot requires following to boot properly :

  • Uimage load address set to 0x2000040
  • Patched initramfs to ignore BOOT bootargs
  • Initramfs included inside kernel image

Configure environment

Important parameters are : LOADADDR which must be set to 0x2000040 to get an Uboot Uimage which will execute in place and also be compatible with Seagate U-boot.
INSTALL_MOD_PATH must be changed to your rootfs path
DEB_HOST_ARCH must be armhf to match target CPU.
CROSS_COMPILE must link to armhf cross toolchain

# Set architecture
export ARCH=arm
export DEB_HOST_ARCH=armhf
export INSTALL_MOD_PATH=/rootfs/
export EXTRAVERSION=-dart2
export LOADADDR=0x2000040
 
# Set number of GCC threads to match number of cores
export "CONCURRENCY_LEVEL=$(grep -m1 cpu\ cores /proc/cpuinfo | cut -d : -f 2)"
 
#Set toolchain
export CROSS_COMPILE=arm-linux-gnueabihf-

Configure Kernel

Lets configure kernel for our platform. This configuration is minimal, you might want to adapt it depending on your use

cd ${LINUXSRCDIR}
make mvebu_v7_defconfig
make menuconfig

Change following parameters :

CONFIG_UNIX Enable #necessary for udev
CONFIG_PACKET Enable #to get ping answers
CONFIG_DEVTMPFS Enable #Necessary for Debian InitRamfs
CONFIG_INITRAMFS_SOURCE /rootfs/boot/initramfs.cpio  #This must be adjusted depending on your configuration 
INITRAMFS_ROOT_UID 0
INITRAMFS_ROOT_GID 0
CONFIG_RTC_DRV_DS1307 Enable# Enable RTC Driver
CONFIG_EXT4_FS Enable#Not mandatory but useful
CONFIG_CGROUPS Enable # Mandatory for SystemD
CONFIG_AUTOFS4_FS Enable
CONFIG_FANOTIFY Enable

Make and install modules

We first make modules and install them inside our rootfs

make modules
make modules_install INSTALL_MOD_PATH=${ROOTFS}

Generating initramfs

We first generate Debian initramfs inside our future rootfs

#Generating initramfs
mount -o bind /dev/ ${ROOTFS}/dev
mount proc -t proc ${ROOTFS}/proc
 
export DEBIAN_FRONTEND=noninteractive 
export LC_ALL=C 
export LANGUAGE=C 
export LANG=C 
 
chroot ${ROOTFS}  update-initramfs -c -k ${KERNELVERSION} 
 
umount ${ROOTFS}/proc
umount ${ROOTFS}/dev

Patching initramfs

To patch initramfs, we need first to unpack it with gunzip, then to extract CPIO archive.
We will then patch init script to ignore BOOT bootarg passed by Uboot.
We will also create missing static devices nodes to get console feedback befor udev is started up.
Finally, we will pack initramfs as a cpio archive to include it inside kernel image.

#Unzip generated Initramfs
cp ${ROOTFS}/boot/initrd.img-${KERNELVERSION} ${ROOTFS}/boot/initramfs.gz
gunzip ${ROOTFS}/boot/initramfs.gz
 
#Extract CPIO Archive
mkdir ${ROOTFS}/boot/temp
cd ${ROOTFS}/boot/temp
cpio -i --no-absolute-filenames < ../initramfs
 
#Apply patch on initramfs init file
patch init < ${BASEDIR}/initramfs-init.patch
 
#Creating missing devices nodes to get console
mkdir ./dev/
mknod -m 622 ./dev/console c 5 1
mknod -m 666 ./dev/null c 1 3
mknod -m 660 ./dev/ttyS0 c 4 64
 
#Pack patched initramfs inside cpio
find . | cpio --create --format='newc' > ${ROOTFS}/boot/initramfs.cpio
 
#Clean unused files
rm -rf ${ROOTFS}/boot/temp
rm ${ROOTFS}/initramfs

Compile Kernel

Now that everything is fine, it is time to compile the kernel and copy it to our rootfs.

#Make UImage
cd ${LINUXSRCDIR}
make uImage
cp ./arch/arm/boot/uImage ${ROOTFS}/boot/

Step 4 : Generate HDD image

Now that we have all elements, it is time to put all parts together inside an image file.

First step is to create a zero file using DD

# Create raw zero image
dd if=/dev/zero of=${IMGFILE} bs=1M count=5000 

Then we use sgdisk to create partition layout in our Image.
We will fake original NasOS Layout with following partitions

  1. Grub : Used to boot system on x86 machines, not used in our case
  2. Boot Rescue : Stores the rescue system, not used in our case
  3. NV Data : Used to store number of failed boot and others flags
  4. Rootfs : Partition on which Uboot is looking for the system

Important information is that Partition #3 must contain NVData like on Original NasOS and that Partition #4 must contain linux system. Both parittions must be formated in ext2fs.

# Creating partitions
sgdisk ${IMGFILE}
sgdisk -n 1:0:+10M -c 1:"grub_core" -t 1:ef02 ${IMGFILE}
sgdisk -n 2:0:+10M -c 2:"boot_rescue" -t 2:8300 ${IMGFILE}
sgdisk -n 3:0:+10M -c 3:"nv_data" -t 3:8300 ${IMGFILE}
sgdisk -n 4:0:+2000M -c 4:"root" -t 4:8300 ${IMGFILE}
sgdisk -n 5:0:+500M -c 5:"swap" -t 5:8300 ${IMGFILE}
 
# mounting image
/sbin/dmsetup remove_all
kpartx -av ${IMGFILE} 
sleep 1
 
# creating file systems
mkfs.ext2 -F /dev/mapper/loop0p1
mkfs.ext2 -F /dev/mapper/loop0p2
mkfs.ext2 -F /dev/mapper/loop0p3
mkfs.ext2 -F /dev/mapper/loop0p4
mkswap /dev/mapper/loop0p5

Final part is simply to copy our previously generated rootfs and nvdata inside image file.

# mount rootfs partition from image
mount /dev/mapper/loop0p4 ${MNTDIR}
cp -ax ${ROOTFS}/* ${MNTDIR}
 
#Unmount rootfs
umount ${MNTDIR}
 
#Mount nv_data partition
mount /dev/mapper/loop0p3 ${MNTDIR}
cp -ax ${NVDATADIR}/* ${MNTDIR}
 
# Unmount nv_data
umount ${MNTDIR}
 
# unmount image
kpartx -d ${IMGFILE}

Step 5 : Flash Image and run system

Image flash can be done using dd command as following

dd if=image.img of=/dev/sdx

Now you can insert HDD in your Seagate Nas. After 1 minute, it will ask for an IP to your DHCP server. You can connect to it using SSH.

  • Login is root
  • Password is root
  • Bookmark at
  • Bookmark "Install Debian on Seagate Nas 2bays" at del.icio.us
  • Bookmark "Install Debian on Seagate Nas 2bays" at Digg
  • Bookmark "Install Debian on Seagate Nas 2bays" at blogmarks
  • Bookmark "Install Debian on Seagate Nas 2bays" at Google
  • Bookmark "Install Debian on Seagate Nas 2bays" at Facebook
  • Bookmark "Install Debian on Seagate Nas 2bays" at Twitter