Reloaded

From NAS-Central Zyxel Wiki
Jump to: navigation, search

Introduction

A Berlin-based developer named "fonz" created a kernel module for the DNS-323 called 'reloaded.ko', with the function to reboot the system with a different kernel, rootfs and/or initramfs. This module has been ported to the NSA-220, and is for download here

Purposes

Booting your own kernel

Let's say you want IPv6. Using the GPL sources provided by ZyXEL it is easy to build the needed kernelmodules, but they don't load due to unresolved functions. Using reloaded.ko I could compile a kernel with IPv6 enabled, and use usb_key_func.sh to load it:

#!/bin/sh

if cat /proc/cmdline | grep reloaded ; then
	# The kernel is already reloaded
	# Insert traditional usb_key_func.sh code here
	exit 1
fi

# create an empty initramfs
touch /tmp/initramfs 

CMDLINE=` cat /proc/cmdline `
sync
/sbin/insmod /mnt/parnerkey/reloaded.ko kernel=/mnt/parnerkey/zImage initrd=/tmp/initramfs cmdline="$CMDLINE reloaded"

# If we advance till here, something went wrong.
echo Oops! Reloading failed. Check dmesg
exit 0

This will reboot the box with the new kernel. (BTW, this doesn't need to be a Linux kernel. In theory you could provide a NetBSD kernel either, given you can build one with the needed drivers)

Booting your own rootfs

Let's say you want to use a modificated firmware. Then you *could* copy the firmware rootfs to usbstick, and load it using usb_key_func.sh (the usb device needs to be formatted ext2/3 for this):

#!/bin/sh

if cat /proc/cmdline | grep reloaded ; then
	# The kernel is already reloaded
	# Insert traditional usb_key_func.sh code here
	exit 1
fi

# find the current device:
usbdev=` cat /proc/mounts | grep /mnt | grep -v ram | awk '{print $1}' `

# find current mountpoint
mountpoint=` cat /proc/mounts | grep $usbdev | awk '{print $2}' `

# check if we already have a kernel:
if [ ! -f $mountpoint/zImage ] ; then
	dd if=/dev/mtd0 of=$mountpoint/zImage
fi

# check if we already have a copy of the firmware:
if [ ! -f $mountpoint/etc/Zy_Private ] ; then
	dd if=/dev/mtd1 of=$mountpoint/firmware
	mkdir /tmp/firmware
	mount $mountpoint/firmware /tmp/firmware
	cp -pr /tmp/firmware/* $mountpoint
	umount /tmp/firmware
fi
 
# Create an empty initramfs
touch /tmp/initramfs

# generate a commandline
for cmd in ` cat /proc/cmdline `; do
	case $cmd in
		root=*)
			CMDLINE="$CMDLINE root=$usbdev"
			;;
		rootfstype=*)
			# Not needed, and maybe even contra-productive
			;;
		*)
			CMDLINE="$CMDLINE $cmd"
			;;
	esac
done
# add a delay, needed for USB device
CMDLINE="$CMDLINE rootdelay=10"


/sbin/insmod $mountpoint/reloaded.ko kernel=$mountpoint/zImage initrd=/tmp/initramfs cmdline="$CMDLINE reloaded"

# If we advance till here, something went wrong.
echo Oops! Reloading failed. Check dmesg
exit 0

This didn't work too well for me. Starting Samba costs ages, and after that it doesn't work either. But, hey, it's only an example.

Using your own initramfs

Let's say you want to load your rootfs from your internal RAID1 array. Then you can't just use root=/dev/md0 in your commandline, because you'll have to assemble the array first. That can be done in initramfs. Create a root-tree, somewhere, containing a subdirectory bin, sbin, etc, proc, tmp, var, dev, lib, mnt and firmware. Fill them with the absolute minimum amount of needed files. (You can find a statically linked version of busybox here). Create the busybox symlinks, (at least mount, umount, cd, cp, exec and switch_root) and make sure that they link to /bin/busybox or busybox, and not /your/own/path/to/bin/busybox. Further you'll need at least the device nodes /dev/sda2, /dev/sdb2, /dev/md0, /dev/ttyS0 and the firmware /sbin/mdadm Then in the root of your root-tree create an executable script init. For instance

#!/bin/sh

echo starting init...

mount -t proc /proc /proc
mount -t sysfs sysfs /sys

# make /lib available for mdadm
mount /dev/mtd1 /firmware
mount --bind /firmware/lib /lib

# assemble and mount raidarray
/sbin/mdadm --assemble /dev/md0 /dev/sda2 /dev/sdb2
mount /dev/md0 /mnt 

# don't need /lib anymore
umount /lib
umount /firmware

# move mounts to new root
mount --move /proc      /mnt/proc
mount --move /sys       /mnt/sys
mount -t usbfs usbfs    /mnt/proc/bus/usb

cd /mnt
exec switch_root -c /dev/ttyS0 . /sbin/init 

Then use cpio and gzip to create the initramfs. I wrote a script for that:

#!/bin/sh

if [ "$#" != "2" ] ; then
	echo usage $0 <path/to/initramfs> <compressedname>
	exit 0
fi

cd $1
find . | cpio -H newc -o > /tmp/initramfs.cpio
cd ..
cat /tmp/initramfs.cpio | gzip > $2
rm /tmp/initramfs.cpio

Now you can provide this initramfs instead of the empty ony in above scripts.

Putting it all together

Debian without need to flash