This is a Linux kernel module and some userspace support programs.
Loading this module into the HD1000 creates a bunch of virtual
/dev/nbd/*
devices. You can then use the
nbd-client
to attach these virtual devices to a remote
nbd-server
. Because this works at the block device layer,
the nbd devices appear to both userspace and the kernel as if
they are local storage; you can mostly treat them as if they are
local disk partitions, mostly.
USE AT OWN RISK
I make no guarantees that this won't break under stress. I had to play some tricks to create it in the first place, and I have not tested it extensively. Especially when it comes to things like virtual swap devices, bugs can lead to deadlocks. The nbd module here is based on a version that is believed to be safe for swapping.
As this was not built against the exact kernel that is on the Roku, it could conceivably cause hard lockups, lost or corrupt data, or other problems. If you have any critical data on the Roku itself make sure you have a backup somewhere else if you load this module.
Say you want 100M of swap space on the Roku for development, and you don't have a big CF card handy. But you do have a Linux workstation somewhere with enough room for a 100M file. Create the file:
workstation$ dd if=/dev/zero of=swapfile bs=1048576 count=100
Format the file as swap space:
workstation$ mkswap swapfile
Then run an nbd server to make that swap file available over the network. Pick an available TCP port number (example here is 9944):
workstation$ nbd-server 9944 swapfile
On the Roku, load the module to make the nbd infrastructure available:
hd1000# insmod nbd.o
Set up one of the nbd devices on the Roku as a client of the
workstation. I'm using /dev/nbd/0
here but it could just
as easily be a different one such as /dev/nbd/27
:
hd1000# nbd-client workstation 9944 /dev/nbd/0
Now /dev/nbd/0
on the Roku appears to be a 100M local
device formatted as swap space. So just turn it on:
hd1000# swapon /dev/nbd/0
This works equally as well if swapfile
is a disk
partition on the workstation. I've been using a 512M logical volume
myself. I'd expect it to also work with a sparse file, which would
make the initial creation of the file go much faster.
A precompiled nbd.o
kernel module loadable into the Roku
1.5.11 firmware. PLEASE SEE WARNINGS ABOVE.
nbd 2.6.0 userspace client and server tools, precompiled for the Roku 1.5.11 firmware.
nbd 2.6.0 userspace client and server tools, precompiled for x86 Linux, glibc 2.2.3.
nbd userspace tool sourcecode. Authoritative source is sourceforge.net. I have a mirror here.
Linux mainline kernel sourcecode, used to create the precompiled module. Authoritative source is kernel.org. I have a mirror here.
Linux mainline kernel sourcecode, used to create the precompiled module. Authoritative source is kernel.org. I have a mirror here.
As of this writing the Roku kernel doesn't ship with nbd support, and the nbd driver in the kernel version they're using wouldn't necessarily be safe anyway since there are some known races in older versions. Here is the procedure I used to create this module.
I did this back in December 2003, so some of the stuff here is a little out of date. Some notes on the setup:
/opt/roku
is a directory on a workstation, exported
with Samba so that the Roku can mount it.
/tmp/Volumes/dododge-roku
is how the mounted
/opt/roku
can be accessed from the HD1000.
/opt/roku/devel
is a directory that is a+rwx
,
so that the Roku can write into it over SMB. In my
configuration /opt/roku
is owned by roku:roku
but smbd
writes to it as nobody:nogroup
.
First prep the Roku. We need the SDK:
on workstation, dir is/opt/roku/devel
mkdir sdk cd sdk unzip RokuSDK_1.5.11.zip
I need my flash card for other purposes, and in any case at 32M it isn't big enough to hold the SDK. So I'll be running the SDK via the SMB share. This means the start script needs to be changed:
on workstation, dir is/opt/roku/devel/sdk
mv MountSDK.roku MountSDK.roku.orig create MountSDK.roku #!/bin/sh losetup /dev/loop/0 /tmp/Volumes/dododge-roku/devel/sdk/rokudev.cramfs mount /dev/loop/0 /usr/share/rokudev -o ro killall taskview on roku, dir is/tmp/Volumes/dododge-roku/devel/sdk
./MountSDK.roku
I know from working out this procedure that the Roku is unlikely to have enough memory to run the SDK. So I'll use my 32M CF card as swap. The card is partitioned with 1 partition, and had been formatted with FAT16. I originally experimented with making the entire partition a swap device, but then I found that there's no mkfs for FAT16 on the Roku, which makes reverting the card to a filesystem when I need to flash new firmware painful. So I'll use a swap file instead:
on roku mount -o remount,rw,noatime \ /dev/ide/host0/bus0/target0/lun0/part1 /mnt/flash1 dd if=/dev/zero of=/mnt/flash1/swapfile bs=1048576 count=30 mkswap /mnt/flash1/swapfile swapon /mnt/flash1/swapfile
Since the Roku is using 2.4.18 plus ATI-only-knows-what patches, I'll use 2.4.18 as my baseline. But the nbd driver has an update in 2.4.19 which apparently makes it more usable for swapping, and the are yet further fixes of race conditions and other stuff in more recent revisions. So I'll unpack the 2.4.23 version of the nbd driver itself.
on workstation, dir is/opt/roku/devel
bunzip2 < linux-2.4.18.tar.bz2 | tar xvf - mv linux linux-2.4.18 bunzip2 < linux-2.4.23.tar.bz2 \ | tar xvf - linux-2.4.23/drivers/block/nbd.c \ linux-2.4.23/include/linux/nbd.h mv linux-2.4.23/include/linux/nbd.h linux-2.4.18/include/linux/nbd.h mv linux-2.4.23/drivers/block/nbd.c linux-2.4.18/drivers/block/nbd.c rm -rf linux-2.4.23 chmod -R a+w linux-2.4.18
To get a basic configuration for the kernel, we'll start with the
autoconf.h
header that Roku has in their SDK. We know
that this doesn't match their kernel, but the architecture settings
should at least be close. Here's a perl script that can generate a
.config
file:
on workstation, dir is/opt/roku/devel
create configfilt.pl $und={}; $def={}; $mod={}; while(<>) { (m%\A#undef\s+(CONFIG_[A-Za-z0-9_]+)\s*\Z% && ($und->{$1}='n')) || (m%\A#define\s+(CONFIG_[A-Za-z0-9_]+)_MODULE(\s+1)\s*\Z% && ($mod->{$1}='y')) || (m%\A#define\s+(CONFIG_[A-Za-z0-9_]+)(\s+1)?\s*\Z% && ($def->{$1}='y')) || (m%\A#define\s+(CONFIG_[A-Za-z0-9_]+)\s+\((.+)\)\s*\Z% && ($def->{$1}=$2)) || (m%\A#define\s+(CONFIG_[A-Za-z0-9_]+)\s+(\S+)\s*\Z% && ($def->{$1}=$2)); } foreach $key (keys %{$def}) { delete $und->{$key}; delete $mod->{$key}; print $key,"=",$def->{$key},"\n"; } foreach $key (keys %{$mod}) { delete $und->{$key}; print $key,"=m\n"; } foreach $key (keys %{$und}) { print "# ",$key," is not set\n"; }
Generate the .config
file.
on roku, dir is/tmp/Volumes/dododge-roku/devel
cp /usr/share/rokudev/usr/include/linux/autoconf.h . on workstation, dir is/opt/roku/devel/linux-2.4.18
perl -w ../configfilt.pl < ../autoconf.h > .config
We may also need to fake out some version information, so that
insmod
will be happy to load the resulting module. And we need to turn on
enough stuff to get nbd to compile. Since the Roku uses devfs, we should
turn that on; the module will then automatically create the
/dev/nbd/*
nodes.
on workstation, dir is/opt/roku/devel/linux-2.4.18
edit Makefile EXTRA_VERSION = _dev-xilleon_x220 make ARCH=mips menuconfig General setup + Networking support Block devices m Network block device support File systems + /dev files system support + Automatically mount at boot
In this case menuconfig
will also take care of things like version.h
and the arch
symlinks. But note that it believes we're cross-compiling,
which will confuse the Roku. So get rid of that.
on workstation, dir is/opt/roku/devel/linux-2.4.18
grep -v CROSSCOMPILE < .config > foo mv foo .config
We'll need a temporary directory that's got more space than Roku's tmpfs. I'll put that on the SMB share as well. This will be for things like gcc's intermediate files.
on workstation, dir is/opt/roku/devel
mkdir tmp chmod 777 tmp
Now let's see if it'll compile:
on roku, dir is/tmp/Volumes/dododge-roku/devel/linux-2.4.18
TMPDIR=/tmp/Volumes/dododge-roku/devel/tmp make modules
After a minute or so I have a "drivers/block/nbd.o"
,
about 200k. Will it load?
on roku, dir is/tmp/Volumes/dododge-roku/devel/linux-2.4.18/drivers/block
insmod nbd.o
No errors when loading, and I managed to scrape this out of dmesg before usb-storage spammed it out of the buffer:
nbd: registered device at major 43
I briefly looked at using the above procedure to compile a USB driver,
but found it to be more complicated. The issue with USB is that it
requires PCI support be enabled, and the kernel configuration code for
MIPS automatically forcibly disables PCI support if you don't have
architecture-specific configuration patches to turn it back on. And of
course we do not [yet] have the Xilleon patches that would do
this. You could certainly hack on the
arch/mips/config.in
file manually to work around this,
but I haven't gone down that road yet so I don't know what other side
effects might be in there. In any case knowing about this will
probably save you some confusion if you try for a USB device.
If you've ever looked into nbd, you might have come across
enbd as well, which is an enhanced network block device
system. I did try to get enbd working, without success. The main
problem is that gcc insisted on inserting calls to a
_flush_cache
function, which does not appear to exist
in the HD1000 kernel. I don't know exactly why this was happening,
but I believe it has something to do with trampolines. I tried various
compiler flags without any luck. If you try it, and get the module
to load, I'd be interested to hear how you did it.
Initial release.