20131207

Fixing FreeBSD/arm in stable/9...

Just a quick note. I recently tried to create a FreeBSD-stable 9 image for an Atmel AT91SAM9G20 board I have. It didn't work. So, I tracked down the problems. It turns out that when the unmapped BIO changes went into stable/9 in revision r251874 a single revision (r246881) was missed. This left the ARM busdma API effectively non-functional. Unfortunately, this merge happened before the 9.2 release, so it is quite likely that all platforms of FreeBSD/arm didn't work in 9.2-RELEASE. I've not confirmed this, but the Atmel board I have wouldn't have working networking (and quite likely working USB) in 9.2-RELEASE. A few revisions later, the VM layout changed slightly. This also broke Atmel in a different way. I've corrected both of these issues and as of r259093, and I have my Atmel AT91SMA9G20 board working, at least mostly. There still appears to be an mbuf memory leak in the ate driver that takes the system out after a few hundred megabytes of traffic. This makes it less than completely useful in NFS root operations. My ultimate goal isn't an NFS root, but it is an network server, so I guess I better track the root cause of this down...

20131124

Tracking down the problem...

OK. After fighting several gdb build issues, I gave up on earlier versions. I thought I'd go old school to try to find the problem. First step was to figure out where we were dying. I had only one clue, the crash location form /var/log/kernel:
Nov 24 19:12:02 (none) kernel: emulate_load_store_insn: sending signal 10 to fred(8249)
Nov 24 19:12:02 (none) kernel: $0 : 00000000 9001fc00 ffffffff 0000001f 9fff7b3c 7fff7b40 00000000 00000000
Nov 24 19:12:02 (none) kernel: $8 : 0000fc00 7fff7b44 00000000 ffffffff 80151b78 000067b2 000033d9 80184020
Nov 24 19:12:02 (none) kernel: $16: 0040bb00 7fff7c44 004015c4 00000003 00407ccc 1002340c ffffffff 100267ac
Nov 24 19:12:02 (none) kernel: $24: 00000000 020cfe48 1000b5f0 7fff7aa0 7fff7aa0 0040899c
Nov 24 19:12:02 (none) kernel: Hi : 00000000
Nov 24 19:12:02 (none) kernel: Lo : 0000004e
Nov 24 19:12:02 (none) kernel: epc : 00408b70 Tainted: P
Nov 24 19:12:02 (none) kernel: Status: 8001fc13
Nov 24 19:12:02 (none) kernel: Cause : 00000010
Nov 24 19:12:02 (none) kernel: 8001e9fc 8001eac0 80022bb4 800215b4 8001d6b8 00408a7c
Nov 24 19:12:02 (none) kernel: 00408a7c 0040899c
We know that epc is the address of the faulting PC in this message. So we died at 0x00408b70. Normally, gdb would tell us where this location is. Something is busted with stabs in gcc 3.0 and 3.3, so I couldn't get a good traceback when we died. So, I had to go old school. First, I disassembled the code:
mips-TiVo-linux-objdump -S -d tivovbi > tivovbi.dis
So I needed find 0x408a7c. Looking for it, we find:
408b64: 8c420000 lw v0,0(v0)
408b68: 00000000 nop
408b6c: 3043001f andi v1,v0,0x1f
408b70: 8c820000 lw v0,0(a0) ----- here ----
408b74: 00000000 nop
408b78: 00621007 srav v0,v0,v1
408b7c: 30420001 andi v0,v0,0x1
408b80: 1040007f beqz v0,408d80 main+0x1054
408b84: 00000000 nop
408b88: 8f99822c lw t9,-32212(gp)
408b8c: 00000000 nop
408b90: 0320f809 jalr t9
408b94: 00000000 nop
Sadly, this isn't as helpful as I'd like. There's no STABs interleaved, nor any source listed. This is less useful than I'd hoped, and likely the reason that gdb can't cope either. So what to do? Have gcc tell me the raw assembler that it is listing...
mips-TiVo-linux-gcc -g -DTIVO_S2 -c tivocc.c -S > tivocc.s
So, now we have to look for the 'lw v0,0(a0)' instruction and hope for the best. Trouble is, gcc outputs raw register numbers, so we have to lookup that in OABI v0 is $2 and a0 is $4. So, we have to look for lw\t$2,0($4) in the output:
$LM506:
.stabn 68,0,930,$LM506
lw $2,76($fp)
srl $2,$2,5
sll $3,$2,2
addu $2,$fp,160
addu $4,$2,$3
lw $2,76($fp)
andi $3,$2,0x1f
lw $2,0($4) ----------- here
sra $2,$2,$3
andi $2,$2,0x1
beq $2,$0,$L348
There's other places where this instruction is used, but this the only place where andi comes in the immediate instruction before the lw. The rest matches tolerably well. So we've found where we started. It turns out .stabn structure 930 is the line number. This leads me back to the following line:
if(FD_ISSET(remote_fd, &rfds))
How can this be wrong? It turns out it isn't wrong. Elsewhere, remote_fd is overwritten. But this turns out to be due to a bug in gcc 3.0. When I updated to gcc 3.3, the crash goes away. It turns out that
if (flags & TEXT_MODE && FD_ISSET(0, &rfds) && (ret = read(fileno(stdin), &c, 1)) == 1 && c == 'q')
is compiled such that it corrupts remote_fd. When parens are put around the first bit, the problem also seems to be fixed. gcc 3.3 compiles both of them identically. This has ended unsatisfyingly, since I don't see the bug in the assembler (so maybe it just moves the actual bug such that it doesn't bite this variable). Despite the odd end, I thought I'd share how I traced down what line this was at, in case others could benefit from the techniques.

20131122

Cross building gdb for TiVo series 2. First attempt fails to work.

OK. Flush with pride after the success of building tools for my TiVo, I thought I'd get the program that I built the tools for working. It isn't obvious what's going on, so I thought I'd build the debugger to look at the core files that I'd been able to get.

So, first the build steps:

tar xvf gdb-7.6.1.tar.bz
cd gdb-7.6.1
rm -rf intl texinfo/ sim
mkdir build-gdb
cd build-gdb
../gdb-7.6.1/configure --target mips-TiVo-linux --prefix ~/tivo/tools/mips-tivo --with-lib-iconv-prefix=/usr/local --without-expat
gmake
gmake install

It took a little bit of dorking around to find all the details, but the FreeBSD gdb port gave some good hints.

But this versions must be too new :(. All the core files I was able to generate failed to get a good traceback.

So, I'll give it another shot with an older gdb.

20131117

Building old-school TiVo build tools on FreeBSD 9.2-stable

Intro

As long-term readers of my blog know, I've been nursing along a TiVo HR10-250 for the past few years. It works great for the low-quality material that my younger son loves to watch, plus I can harvest video off of it with ease.

Recently, we switched up how it was connected to our TV (and indeed, got a new TV too). During this process, we lost the ability to display subtitles. Since my wife and I like to watch The Daily Show and other similar shows upstairs without going downstairs to the big TV with the HD DirecTV player, and the environment upstairs can be a bit noisy, subtitles are quite useful.

So, after crawling around the DealDatabase forums for a bit, I found a good program called tivovbi. It works really well for displaying closed captioning. However, I used a binary I found on the forum. Nothing is more annoying than a program you download from a forum that randomly core dumps for reasons that are totally mysterious.

I can't even hack it to do anything since I have no TiVo build tools.  Looking for tools online, I can't really find anything that isn't just a Linux binary.  The Linux binaries have issues with the FreeBSD linux ABI implementation, owing in large part to their age (binaries from 10 years ago have some issues, I think with just the packages are needed having a subtle incompatibility).

So what should I do. I could create a virtualbox VM and run linux. But then I'd be running Linux, and copying back and forth to a VM is always a hassle in some way.

So, the other alternative is to build the tools from source. I thought it would be easy to do this, but there's a number of issues with it, so I thought I'd write up my experience. This is on a FreeBSD 9.2-stable system on amd64. That last bit will turn out to be important in a bit, because nothing was easy and simple on this project...

After reading through these instructions, I can't help but marvel at how this lack of integration is tolerated, but to be fair, this is building tools that are nearly a decade old at this point and I did have to kludge around lack of support for 64-bit x86 in gcc... This is nearly 60 separate commands to type. Yuck. Also, looking at the layout in chrome, many of the line breaks have liberties taken with them, so your best bet may be to cut and paste much of what I'm doing here...

Locating the tools

Tivo Utils has a bunch of useful links. Including the linux binaries that I've had issues with. Thankfully, there's a shell script called 'build_mips_x_compiler.sh' which builds all the tools and the basic libraries. I thought I could just run it and have everything built. As with everything else in this project, this wasn't so much the case. So I wound up doing a lot of things by hand.

The first bit of the script fetches all the source tar balls. The gnu stuff has had long-term stable paths, so they fetched. However the TiVo linux didn't transfer, since it was in a new location. In fact, it was also for 4.0, and my TiVo was running 6.4a. So, I had to grab that from TiVo linux downloads page. The Linux 6.4 download was exactly what I needed to grab. Once I had these in place, I was ready to start building. You also need binutils 2.13Gcc 3.0 (yes, 3.0!), glibc 2.2.3, and glibc 2.2.3 linuxthreads support.

Also, I'm installing all the tools in ~/tivo/tools tree, and building them from ~/tivo/toolchain. Fetch all of the above linked tarballs into ~/tivo/toolchain (or whatever you want). Now that we've found the tarballs, we can start with the builds. I'll assume the following environment variables are set. TARGET is set to "mips-TiVo-linux" and PREFIX is set to "$HOME/tivo/tools". I've also added ${PREFIX}/bin to my PATH (I didn't from the start, and got quite far before it mattered). I also had gnu make installed as gmake from ports.

Building Tools

Binutils 2.13

Binutils 2.13 is almost trivial to build:
cd ~imp/toolchain
tar xvfz binutils-2.13.tar.gz
mkdir build-buinutils
cd build-binutils
../binutils-2.13/configure  --target=$TARGET --prefix=$PREFIX
gmake -j 20 all
gmake install
cd ..

gcc 3.0 stage 1

gcc 3.0 stage 1 took a lot of trial and error to create. Turns out, there's no support for FreeBSD 9 in this tarball. That's trivial to add, and I've provided some patches. However, the next problem is that FreeBSD/amd64 isn't supported. This problem turns out to be more difficult to overcome. So you have to configure for FreeBSD/i386 (or backport amd64 support, which I thought would be too hard, so I didn't do it). This means you need to have a 32-bit compiler. After all the talk about making cc -m32 working, I thought I could just do gmake CC="cc -m32". This failed, however. The 32-bit applications dumped core, meaning that gcc couldn't complete its bootstrap process. I wound up having to use FreeBSD's xdev to do it:
pushd ~/FreeBSD/svn/stable/9
sudo make xdev XDEV=i386 XDEV_ARCH=i386 WITHOUT_CLANG=t
popd
Once we have that in place, we can build gcc. Except that it doesn't build quite right. We need to add some additional patches. One to work around a weirdness in the obstack implementation where it relied on an illegal lvalue autoincrement, and one to work around crazy sh that's likely bogus in fixincl. All of these are included in the above patch.
mkdir build-gcc
cd build-gcc
../gcc-3.0/configure --target $TARGET --prefix $PREFIX --without-headers --with-newlib --disable-shared --enable-languages=c --host i386-foo-freebsd9
gmake CC=/usr/i386-freebsd/usr/bin/cc all-gcc
gmake CC=/usr/i386-freebsd/usr/bin/cc install-gcc
If you wanted to see if -m32 worked, you could skip the make xdev step above and substitute CC="cc -m32" in the two gmake commands. I've also tested values up to 20 for -j for at least the first command.

Building the Linux Kernel headers

The following comes pretty much verbatim from the build_mips_x_compiler.sh and have been verified to work. You'll need to grab this patch for these instructions to work. It works around an expr difference, as well a really cheap kludge to get autoconf.h generated. Also, I had to install the bash port, and create a symlink from /bin/bash to /usr/local/bin/bash, which I've not put inline...
tar xf TiVo-6.4-linux-2.4.tar.gz
cd linux-2.4
patch -p0 < ../tivo-linux-2.4.diff
yes "" | gmake ARCH=mips CROSS_COMPILE=mips-TiVo-linux config
gmake ARCH=mips CROSS_COMPILE=mips-TiVo-linux include/linux/version.h
mkdir $PREFIX/$TARGET/include
cp -rf include/linux $PREFIX/$TARGET/include
cp -rf include/asm-mips $PREFIX/$TARGET/include/asm
which will be enough to get us to the next step...  Woof, maybe I should just make a script for all this stuff... With so many fiddly bits, I'm not sure that's a good idea.

Building gmake 3.80!

Newer versions of gmake don't grok the Makefiles that glibc 2.2.3 generates. All kinds of weird errors and odd behavior. So, to make progress, you'll need to build gmake.
fetch ftp://ftp.gnu.org/gnu/make/make-3.80.tar.gz
tar xf make-3.80.tar.gz
cd make-3.80
./configure
make
cp make ~/bin/gmake380
cd ..
I didn't bother installing it, since I just need it for this diversion so I copied into my bin dir, that I have in my path.

Building glibc 2.2.3

Now we're on to glibc. Things have been smooth sailing up to this point. With glibc, we have to extract, configure, build, fix the build oops, build again, fix some info files, then install. Woof! Sure makes for a difficult to reproduce experience. And those are the build on linux instructions... Apparently there's a lot of host leakage that's making things somewhat difficult to reproduce... but so far that appears to be only with gmake 3.82. gmake 3.80 works much better. More patches needed.
tar xf glibc-2.2.3.tar.gz
tar xf glibc-linuxthreads-2.2.3.tar.gz -C glibc-2.2.3
env CC=mips-TiVo-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix=$PREFIX --disable-debug --disable-profile --enable-add-ons --with-headers=${PREFIX}/${TARGET}/include
gmake380
sed -i.old -e 's/elf32-bigmips/elf32-tradbigmips/' elf/rtld-ldscript
gmake380
gmake380 install
cd ..

Munging things around before the second assault  on gcc for its stage 2

Don't know why the original instructions take this time rearrange the deck chairs, but it seems to be necessary.
mv ${PREFIX}/${TARGET}/include/asm ${PREFIX}/include
mv ${PREFIX}/${TARGET}/include/linux ${PREFIX}/include
rm -r ${PREFIX}/${TARGET}/include
rm -r ${PREFIX}/${TARGET}/lib
ln -s ${PREFIX}/include ${PREFIX}/${TARGET}/include
ln -s ${PREFIX}/lib ${PREFIX}/${TARGET}/lib

Build gcc 3.0 stage 2

Now that we have everything else setup, it is time to build the second stage of gcc. Alas, gcc 4.2.1 doesn't allow constructs like (a ? b : c) = d, which gcc 3.0 uses to implement C++. So, no g++ for me. If you want g++, you'd have to build the gcc34 port... The rest is almost boring after all the other hoops we jumped through:
mkdir build-gcc2
cd build-gcc2
../gcc-3.0/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c --host=i386-foo-freebsd9
gmake CC=/usr/i386-freebsd/usr/bin/cc all
gmake CC=/usr/i386-freebsd/usr/bin/cc install
cd ..

Building stuff

Now, it is time build things...  I'll write more blog entries about that...

20130924

How to fix a Washing machine

Let's say you have one of those fancy washing machines with sophisticated circuitry.

Well, then if your machine is like mine, it sucks to be you.

Last night, before a trip, the Kenmore Oasis HE machine that we've had for many years started doing something weird. You'd turn it on, and it would start cycling from Heavy, to medium, to light, etc on the soil setting. It wouldn't stop doing it. And if you somehow got it to pause for a moment, the cycle would do weird things: spin at the wrong times, drain at the wrong times. And if you left it on overnight, it would suddenly spring to live at 1am just as you were falling asleep.

So, new parts for this would never arrive in time for me to install them before the trip.

So, what to do. I tried all the obvious fixes: reseat all the connectors. Do it again just in case. Get some rubbing alcohol and clean off the accumulated gunk on the board. None of these fixed the problem. So looking at the board, I thought "geeze, why don't I just remove the switch from the circuit: maybe it's gone bad and shorted out." I mean, if you're falling to earth, you might as well try to fly, right? The switch was wired into the circuit through a diode. Since the diode was SMT and the switch was through hole, I decided to desolder the diode (D59 in the pic). I had no rational basis for thinking this would work. Other folks have reported exactly this same problems on different washing machine forums, but the solution was always "start replacing boards" which wouldn't fly for me today.

So far, it seems to be working. I hope this repair will hold until I get back from my trip...
This photo shows my test run, where I just removed one side....

Who said these new washing machines are irreparable... Oh wait, all the repair guys that have come out and all the online forums, and this isn't really a fix so much as a kludge until I can get back to fix it right...

20130903

What could be so hard about an external toolchain.... Step 1: How big a problem...

FreeBSD is moving from gcc to clang as its base compiler. This works really well for x86, and moderately well for arm. However, it doesn't work very well for any other architecture that FreeBSD supports.

Brooks Davis recently committed changes that he claims allow him to build FreeBSD/mips with an external clang and the cross-binutils port.

I thought "how hard can that be, I'll knock together a port for gcc that lets me use that instead of the native compiler.

So, with a little bit of svn foo, I was able to extract the differences in FreeBSD's gcc from the stock 4.2.1 gcc that it is based on. I thought the differences would be small and manageable. However, they were large. In excess of 10,000 lines in the diff file.

Undaunted by this large size, I started breaking down the diffs. Well, first, the diffs, excluding the docs, are 10,652 lines in size. I didn't save how big they were with the docs included.

So I went to separate out the wheat from the chaff. First up is 5172 lines of changes to x86. Why do we need that many changes to x86? Well, to support newer x86 hardware models. since I assume that will be in a newer version of gcc, I chose to totally ignore it unconditionally.

Next, I discovered 924 lines of changes for the FreeBSD configuration of gcc, plus various tweaks to gcc to make it the FreeBSD native compiler. Half of these seem relevant, the other half not so much (I'll discover how much later).

There's also about 2187 lines of bug fixes that are split between back-ports of gcc bug fixes and various warning cleanups to clang will be more happy. Add to that another 340 lines of g++ modernization...

So we're down to less than 2k lines of changes here. They break down as 220 for arm, 675 for mips, 220 for ia64, 245 for sparc and 350 for powerpc (total of 1910) and another 78 line for threading tweaks, 135 for code to check FreeBSD's kernel's printf extentions, and 130 for some tweak to assembler output that I don't quite get, so it goes into the 'look at it later to see if it is still needed' pile.

The first 4 patches slotted into the gcc 4.5 nicely (config-guess changes, the config + arm + mips changes). After tossing out all the extra goo we had been dragging around in our tree, they are about 850 lines of diffs. After adding in the other architectures, I suspect this will double. Plus the other relevant gcc changes, we may see as many as 2000 lines of patches for any port that could be used as a system compiler for any supported architecture).

I have the beginnings of that port, but it is early days. It builds, but still can't make it through buildworld let alone buildkernel. The external toolchain support needs a lot of tweaks to make it happy with gcc, and there's still much I don't understand about why some of them are necessary.  But I'll save those for another time.

Anyway, that's enough for now. I'll report also on moving these patches to 4.6, 4.7, 4.8 and 4.9 when  get around to it. I'll also see what it takes to move them into upstream sources. That should have been done years ago, but that's another tale of woe I don't have time for just now, and even if I did I'm not sure that dirty laundry would be appropriate for my hacking blog.

How C can bite you, an example

Consider the function foo:

int foo() { if (error) return -1; else return 12; }

and consider its use here:

int n;
...
if ((n = foo()) >= sizeof(bar)) { memcpy(dst, src, n - sizeof(bar)); }

Seems simple and safe right? Well, not so much.  The 'C' standard states that when you have types that aren't of the same rank, a conversion must happen. So, since n is an int, and sizeof(foo) is a size_t (unsigned long), a weird conversion happens when you hit an error in foo. It returns -1, but that -1 is converted to MAX_ULONG, so the conversion is true, and we copy way too much memory smashing everything in it's path.

When a coworker asked me about this, I replied "And verily, thou shalt not compare an int to a size_t when thine int can be that which represents a plurality of deficit as well as a plurality of surplus." because it is easily clearer than the C standard...

20130111

TivoWebPlus 2.1 changes

As you may know, I still have a HR10-250 in service.  I run TivoWebPlus 2.1 on the box. It mostly works the way I want it, although at times it is a bit slow.

I checked out the latest version from the sourceforge web site many months ago and found there's some issues with it that I'd like to fix.

I'e made the following fixes:

  1. Sadly, I didn't document very well where I got this fix from. It makes Movies show up as Movies and not as 'Not an Episode' in the ToDo and Now Playing fields. This appears to be a combination of my hacking, but mostly the work of "DJL". I think I downloaded it from a dealdatabase or other tivo forum posting, but I can't find it now.
  2. Fixed the long series number problem so episode numbers are properly displayed.
  3. Added a Thumb link so you can put those in your ToDo lists. I find this handy for quickly killing those things that Tivo thinks I might like, but I don't.
  4. Fixed a problem with descriptions being nothing but spaces (this may have also been a forum find, but I can't find docs for that either)
  5. Fixed a few problems with todofeed.tcl (not sure these are completely good, as I think I was trying to parse the output for something I did differently).
  6. Fixed a spelling error.
OK, these changes won't change the world, but since all work has stopped on TivoWebPlus, I thought I'd share them with the world.  You can find my cumulative patches here. If anybody recognizes #1 or #4 or can locate their origin, please let me know by commenting

I've also hacked together a todo database publishing api. It is crude, but it allows me to cancel shows I've already downloaded via ftp and such.  On the off chance people find it useful, you can find it here.

If you find these things useful, please comment. Not sure how many people may be interested, or if the TiVo hacking world has totally moved beyond this device...


20121224

Some notes on HR10-250 video

Over the past 5 or 6 years, I've had my TiVo HR10-250 setup to extract videos off of it.  Please see my other posts on how I set that up with Zipper and mfs_ftp.  There are some newer programs to help with the video extraction, but I have a cobbled together system that works OK enough for now, so I'll not go into those here.  Today I'll explore how to convert the files mfs_ftp can produce into something that looks good, at least on the TV I have :). I'm in the US, so all these instructions are NTSC-centric. Sorry for all my pals out there that have PAL.

What I will talk about is converting the tmf files (or the .ty files) into something useful. For me, useful varies with time. The tmf files are like ty files, except they are big tar balls of a series of .ty files (all smaller than some limit that I can't recall) and a xml file that describes the show. The tytompeg program is what I use to convert them to a mpg file. You can find info on how to snag this here DVRpedia entry on TyToMpg.

The tytompg program produces video that is 480x480 with a 4:3 pixel aspect ratio.  This turns out to be the SVCD resolution, so many tricks for turning SVCDs into DVDs work when processing these files. However, they aren't fully compliant SVCD files. There's some audio delay issues that cause problems and many tools have difficulties with these files. I've only overcome the synchronization problems by trial and error at this point (certain ffmpeg operations causes something to remove the stutter, sometimes on some versions). One problem with tytompg is that I lose the subtitles. I'll explore that problem more later...

A number of cartoons are broadcast these days on the SD stations in letterbox. My son watches them. It would sure by nice if I could process these files to produce a nice, 16x9 videos that play nicely. Since these files are 480x480, the actual video is in the pixels from 8,60 to 472,360 (the extra 8 pixels is a band that many stations seem to put around the picture for reasons unknown). Sometimes there's only a few pixels on each side, so it isn't worth the hassle to get rid of them (in which case the picture is bounded by 0,60 to 480x360). 720x480 is the only DVD resolution that supports a 16:9 aspect ratio. Speaking of aspect ratios, please see the writeup at http://howto-pages.org/ffmpeg/ which covers this in extreme detail. Here's the ffmpeg 1.0.1 command line I use to convert them (the 0.x command needs to crop based on the 720x480 image size).

ffmpeg -i 002-ty.mpg -vf yadif,crop=464:360:8:60,scale=720:480 -aspect 16:9 -vcodec mpeg2video -s 720x480 -b 4500k 002-nice.mpg

mpeg2video is easy to create and fairly ubiquitous, but has a couple of draw backs.  First, it is large. The above command typically doubles the size of the file. It looks really nice on the big screen HD TV (so ffmpeg's upscaler is a little better than the upscaling in the TV), but eats up the storage space. Second, many of the media renders I have in the house do mpeg2 rendering in software, so the playback can be a bit jerky on those devices.

Converting to h.264 is an option that I'll explore in later columns. The current level of tool integration isn't so nice, so would be a much longer write up.

20120927

DirecTiVo HR10-250 restore

I had to move the hard drive between two TiVos recently.  Since it was on DirecTV, I got the dreaded Error #51.  Since I couldn't recall what I did last time I got it, I googled it, only to find I needed to reset the unit with a Clear and Delete Everything (C&DE).  Turns out that since I'd hacked the TiVo, I had a much easier option that I'd forgotten about.

Sadly, I cleared everything before I'd discovered this much easier option.  I'm linking the TiVo forum post from here so that my future self will look at it before I have to go through this pain again.  Good thing I saved all the hacks I'd done to the TiVo along the way...

Recovering from Error #51

Hopefully I can easily recover the steps. Zipper sure makes it easy. It also adds the Enhancement Script that's knocking around to do all kinds of useful things. Makes hacking the TiVo way too easy...  Normally I would scoff at this script, but it is a good aggregation of knowledge that's hard to come by elsewhere, except sifting through the detritus of three or four different TiVo forums.

Anyway, just random hacking away...  Maybe the newer direct tivos can be hacked so I can download HD data again...

Oh, and one other thing: The zipper iso that's created can be booted in virtual box. If you connect your hard drive via a USB to PATA adapter, then you can connect that to the same virtual box.  The trick I found here was to create a vmdk that pointed to the drive.  When it is /dev/disk1 on my mac, I just do "VBoxManage internalcommands createrawvmdk -filename ~/TiVoDrive.vmdk -rawdisk /dev/disk1" and then connect that using the Storage tab in the config dialog for the virtual machine in VirtualBox. Handy stuff that...



20120727

FreeBSD/arm booting on SAM9260-EK to multiuser

Woot!  After working hard to get the SAM9260-EK rescued, I'm able to boot SAM9260-EK to multiuser.

Here's the dmesg:
Copyright (c) 1992-2012 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
 The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 10.0-CURRENT #13 r238762:238811M: Thu Jul 26 23:10:37 MDT 2012
    imp@dune.bsdimp.com:/dune/imp/obj/arm.arm/dune/imp/FreeBSD/sys/SAM9260EK arm
CPU: ARM926EJ-S rev 5 (ARM9EJ-S core)
  DC enabled IC enabled WB enabled LABT
  8KB/32B 4-way Instruction cache
  8KB/32B 4-way write-back-locking-C Data cache
real memory  = 67108864 (64 MB)
avail memory = 61501440 (58 MB)
atmelarm0: 
at91_pmc0:  mem 0xdffffc00-0xdffffcff irq 1 on atmelarm0
at91_pmc0: Primary: 18432000 Hz PLLA: 198 MHz CPU: 198 MHz MCK: 99 MHz
at91_wdt0:  mem 0xdffffd40-0xdffffd4f irq 1 on atmelarm0
at91_wdt0: Watchdog disabled! (Boot ROM?)
at91_rst0:  mem 0xdffffd00-0xdffffd0f irq 1 on atmelarm0
at91_rst0: Reset cause: Software Request.
at91_pit0:  mem 0xdffffd30-0xdffffd39 irq 1 on atmelarm0
Timecounter "AT91SAM9 timer" frequency 6208000 Hz quality 1000
at91_pio0:  mem 0xdffff400-0xdffff5ff irq 2 on atmelarm0
at91_pio1:  mem 0xdffff600-0xdffff7ff irq 3 on atmelarm0
at91_pio2:  mem 0xdffff800-0xdffff9ff irq 4 on atmelarm0
at91_twi0:  mem 0xdffac000-0xdffaffff irq 11 on atmelarm0
iicbus0:  on at91_twi0
iic0:  on iicbus0
icee0:  at addr 0xa0 on iicbus0
at91_mci0:  mem 0xdffa8000-0xdffabfff irq 9 on atmelarm0
mmc0:  on at91_mci0
uart0:  mem 0xdffff200-0xdffff3ff irq 1 on atmelarm0
uart0: console (115200,n,8,1)
uart1:  mem 0xdffb0000-0xdffb3fff irq 6 on atmelarm0
uart2:  mem 0xdffb4000-0xdffb7fff irq 7 on atmelarm0
uart3:  mem 0xdffb8000-0xdffbbfff irq 8 on atmelarm0
uart4:  mem 0xdffd0000-0xdffd3fff irq 23 on atmelarm0
uart5:  mem 0xdffd4000-0xdffd7fff irq 24 on atmelarm0
uart6:  mem 0xdffd8000-0xdffdbfff irq 25 on atmelarm0
ate0:  mem 0xdffc4000-0xdffc7fff irq 21 on atmelarm0
miibus0:  on ate0
ukphy0:  PHY 0 on miibus0
ukphy0:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
ate0: Ethernet address: 3a:1f:34:08:54:54
ohci0:  mem 0xdfc00000-0xdfcfffff irq 20 on atmelarm0
usbus0 on ohci0
Timecounters tick every 10.000 msec
usbus0: 12Mbps Full Speed USB v1.0
Root mount waiting for: usbus0
ugen0.1:  at usbus0
uhub0:  on usbus0
uhub0: 2 ports with 2 removable, self powered
Root mount waiting for: usbus0
Root mount waiting for: usbus0
ugen0.2:  at usbus0
umass0:  on usbus0
Trying to mount root from ufs:/dev/da0s1a []...
mountroot: waiting for device /dev/da0s1a ...
da0 at umass-sim0 bus 0 scbus0 target 0 lun 0
da0:  Removable Direct Access SCSI-0 device 
da0: 1.000MB/s transfers
da0: 483MB (990976 512 byte sectors: 64H 32S/T 483C)
warning: no time-of-day clock registered, system time will not be set accurately

I'll have to try the macb driver to see if it is any faster than the ate driver. No clue if it is working well or not.
I'll have to migrate over to booting off the NAND from the Dataflash I'm booting off of now. Having the SD card in the slot during early boot hangs because on this board both the SPI0 dataflash and the MMC are hard wired to the same, well, wires. This means I should get the nand and nandfs stuff working on this board as well, so I can boot off of its 256MB flash.
Plus I need to get back to refactoring. After editing board_sam9260ek.c I can see that I need to extend the AT91RM9200 device stuff I've done to the sam9260 (and sam9g20). But I'm not sure how far I want to go down that path. But we need some way to have a generic pin mux system. Linux has a fine example.
However, I think that many of the issues that I'm running into may be solved by moving to device-tree stuff. Other ARM ports support this now, and Linux is moving that way. Newer Atmel CPUs will have DTS files. All boards supported by Linux appear to be getting DTS files to replace the custom code for each board. It seems that this is a good way to go. AT91RM9200 is the only one that seems to not have dts files, so I may need to write those from scratch.
But the bottom line is that I'm excited. I'd given up hope on this board, and now it is booting. Woo hoo!

20120713

AT91SAM9260-EK restored!

Quite some time ago, I received a AT91SAM9260-EK board from Atmel.  I tried to turn it on at the time, and it looked dead.  I put it on the shelf and got busy with other things: new jobs, a divorce, a new marriage, a son, and a new house.

Recently, I became interested in the Atmel SoCs again (Atmel's open source group recently gave me some hardware to evaluate some work).  I took this board out of the closet and it seemed dead.  But one night I had the serial port connected and noticed that the ROM recovery program printed something.  I tried to download things with my old AT91RM9200 spi recovery program, but that didn't work.  I tried running Atmel's SAM-BA on FreeBSD, but it couldn't communicate with the board.  I tried using openocd with SAM-ICE.  Sadly, the board was wired for ICE, not JTAG and the instructions for doing the conversion online didn't work.  Finally, in an act of desperation I installed Ubuntu in as a Virtual Machine image.  With that, it worked.

So now, I have new shiny to play with that should already be supported by FreeBSD so I can make sure that I'm not breaking any at91sam9 support with my recent changed.

20120607

Wish me luck: taking the git plunge

Wish me luck.

I just typed the following commands:

  • git clone https://github.org/freebsd/freebsd-head.git
  • cd freebsd-head
  • git branch army
  • git checkout army
and started my own local branch.  Wish me luck.  Oh, I've said it, but with git, I think I might need it.  I actually didn't type exactly the above, but that's what I should have typed.  git reset seems to have been my friend.  We'll see next time I pull from github...  and if I can get the rebase command to work for me better than mercurial has been working for me at work.

Now, to figure out how to do  a similar thing to patch queues, except I really want to just correct commits rather than use a whole different set of commands.

Unifying arm boot arg parsing

Greetings again,
Here's a slightly edited version of a post I made to the FreeBSD arm list, proposing a path forward to cleanup and unify boot arg parsing on arm and at the same time add support to all boards for parsing FreeBSD's /boot/loader metadata as well as Linux's uboot/redboot meta data. Thought you might be interested.
For too long parsing boot args in arm land has suffered from cut and paste code. This is inefficient and inflexible. This patch does something to fix that. First, it modifies all the arm ports to call parse_boot_param passing in the boot parameters from initarm as the first thing in each platform's implementation of that function. This is done really super early, importantly before we start using memory outside of the loaded kernel's text, data, and bss areas. I'd thought of moving this even earlier, into __start just before the call to initarm, but wasn't completely sure was quite right (it would be more code deleted, however, if I do that: please comment). The down side is that initarm was the only function we called in __start apart from mundane things like memcpy and that would change that, but that's kinda a weak argument I think. Also, it returns the last memory location, which would be lost if I called this from __start..
I've created a weak alias to tying this function to fake_preload_metadata. All but one of the ports do this now, and this moves them to a common standard that could be more easily changed.
For most ports, it replaces the call to fake_preload_metadata. As such, I've modified the signature of fake_preload_metadata to be the same as parse_boot_param and made it a weak alias. So, if you don't define one, you'll get the current behavior.
In a future patch, I'll likely be moving the mv platform's code into this routine (I'll create a default_parse_boot_param and create a weak alias pointing to that instead). I'll need to modify the mv port to then get the dtb blob via the metadata, or possibly create a new global for it so that other platforms might make use of that also.
In a patch after that, I may add a kernel option to enable creation of FreeBSD /boot/loader metadata from Linux's standard boot stuff. This will allow platforms to get more data from the Linux boot loader without going through the intermediate /boot/loader. But it should preserve a unified interface by having it behave just like /boot/loader, but without anything setup by its more advanced features like kernel environment variables or loadable modules.
If I've done things right by this point, then any ARM port can take advantage of these new features, not just the target I'm aiming at. In addition, anybody can use their own boot loader, if they so choose, and be able to write custom code that parses the args from it in whatever appropriate way might arise for their board. I know of at least one FreeBSD/arm user that has a heavily hacked boot2 boot loader that passes things into the kernel in a non-standard way. This will accommodate them, and others like them, while still providing the project with useful functionality.
Comments?
P.S. You can find the patch here.

20120603

Rearranging the deck chairs in the ARM port

Recently, I've been trying to catch up with some of the technical debt that the FreeBSD/arm port has accumulated.  Some of that technical debt was my fault, of course, but some of it wasn't.  I don't really much care whose fault things were,  but I would like to get things cleaned up.  Some of these are paths not taken.  Some are porting shims that never got properly connected.  There's also some features that were poo-poo-ed by some (including me) years ago that seem to make more sense now.

None of this stuff is terribly sexy.  Some of it will be addressed by the summer of code project that's working its way through some of the maze of twisty passages in initarm() that are subtly different between the different boards for no good reason.

We have no common place for boot loader code.  Some arm ports do use a common routine to fake up just enough metadata that debugging and other symbols work.  Some arm ports assume a full /boot/loader is present.  However, there's no common facility for getting information from via the Linux boot protocol, nor is there any provisions for having multiple boards supported by a single kernel.  There's no uniform interface to get this information that might be passed in by other means.  There's no real way for a board to get control early enough to get at meta-data a custom boot loader might pass in.

The first big thing that I'd like to comment on is a small change to the interface between locore.S' _start routine and the first port-specific code in initarm.  I've preserved the first 4 registers that were passed in on boot to _start().  Before, there'd be no way to access the Linux ATAGs, for example, by a port since these are passed in as arg 3.  To allow for future expansion, I'm just passing in one structure now.

In the coming weeks, I'll be implementing routines to parse these arguments based on standard boot protocols, while allowing customization for special needs.

In the coming months, I plan to expand our support for having multiple boards based on a single Atmel SoC.  Once I have the one at a time SoC code working, I hope to get multiple SoCs working in one kernel.  While the extra 'bloat' isn't optimal for many users, the convenience of being able to boot one kernel for installation, or trying out the system, is a feature that's been much requested.  I've already eliminated the need to have a compiled-in master clock frequency, with improved main clock detection with fallback for people using unconventional frequencies.

I'm also interested in sweeping into the tree many of the Atmel arm changes that have been accumulating in the PR database.  Some of these will be easy to integrate, while others may be difficult due to drift from the original submission.

Once we get a good baseline, I hope to merge these changes into 9.x and 8.x.  To date, the interfaces that have change have been purely internal ones we do not support.  External users may experience some bumpy waves if they haven't been working to get their changes merged upstream.  The more that you've submitted, the more I'm likely to go the extra mile to help smooth any transitions.  With luck, 8.3 and 9.2 will both benefit from these efforts.

20120602

FreeBSD Driver book

I recently received a complementary copy of the book FreeBSD Device Drivers by Josheph Kong. I also had the pleasure of meeting Josheph Kong at BSDcan 2012 a few weeks ago.
This book serves as a good introduction to all kinds of drivers and kernel modules in FreeBSD. It explores the basics of each kind of driver, complete with an example driver from the FreeBSD tree for each of the types of drivers that it describes. Joseph annotates the code to explain what each part of the code examples do, as well as to highlight the relevant areas for people wishing to write their own driver.
I'd recommend the book for anybody that needs an introduction to drivers. The walk throughs will get people up to speed, as well as introduce many of the uniquely FreeBSD quirks one needs to know to integrate with FreeBSD. The explanations are clear and concise and provide good coverage of the material.
Advanced developers will find some good nuggets in the book as well. Many of the explanations go into enough detail that even advanced users will learn things about FreeBSD from the book. Since the book sticks to the simple topics, some advanced users may be disappointed to find that some advanced topics have been omitted from this book. While many of them are very esoteric, the one I would have included would have been a discussion about how network drivers interact with struct ifnet. While other books cover that in detail for a generic BSD system, having that covered in this book would have been very beneficial. A companion book covering these topics would nicely fill the gaps here, should No Starch Press decide to publish it.
The FreeBSD world has been without any good device driver book in English for a long, long time. This book is a welcome addition. I hope it is but the first book of many from Joseph in this area.

20110529

Canon Rebel Xt and 32GB CF

Just thought I'd mention that I've been using a 32GB CF card with no special formatting in the Canon Rebel Xt. It has been working great for years.

20110202

How to run something other than login on a tty

Sometimes you don't want to run login on the console or other terminal. The reasons for this vary. Some appliances want to boot to a shell prompt on the console for debugging purposes (this console typically isn't exposed, so no security problems there). Sometimes you want to use init's restart feature to keep critical daemons alive. I've developed several control and measurement applications that used this feature. Sometimes your want to offer a menu driven interface to your users instead of a cli-based one.

Recently, I had to add support for a menu console to FreeNAS. I couldn't find any immediately available documentation on how-to do this, I had to dive into some little-configured recesses of FreeBSD to make this happen. Thankfully, no code changes to FreeBSD were required to make this work. I thought I'd do a quick how-to here to cover the basics.

We'll start with /etc/ttys. This is the file that has entries like the following:

ttyv0 "/usr/libexec/getty Pc" cons25 on secure

which tells init to run getty with the parameter Pc on /dev/ttyv0 with TERM set to cons25. Getty is a program, for those that don't know, that sets up the tty device for interactive use so that normal interaction works as you'd expect. While one can run programs without getty, especially on a 'device' that doesn't exist, I'll ignore that path for this post. This is about creating an interactive program that runs on a tty device.

The 'Pc' here is the key to understanding what getty is doing. Pc refers to the gettytab entry 'Pc' which looks something like:
P|Pc|Pc console:\
:ht:np:sp#115200:

which, according to the gettytab(5) man page means "Use 115200 baud, no parity, hard tabs". This is great if you want to run login to get an account and password, but what if you want to run a program other than login instead? Maybe one that doesn't know about tty sessions, stdin/stdout redirection etc?

The answer turns out to be fairly straight forward. You just tell tty to use a different entry. This scales well for a small number of programs, but not so well if you have dozens since you can't pass parameters to the final program. For my case, I just needed a menu for FreeNAS. I added the following entry:
#
# FreeNAS menu system entry
#
FreeNAS|freenas|FreeNAS Menu:\
:ht:np:sp#15200:lo=/etc/netcli.sh:al=root:

to /etc/gettytab. This tells getty to run /etc/netcli.sh as root. Since netcli.sh was mucking with the network it had to run as root, but there's no reason it couldn't run as a different user for safety. Once I had this entry in gettytab, I changed the above /etc/ttys line to look like:
ttyv0 "/usr/libexec/getty freenas" cons25 on secure

and sent init a hup with a "kill -1 1" command (the -1 is very important, otherwise you reboot your system). Once init reparsed /etc/ttys, netcli.sh started running.

Normally, that would be the end of it. However, in this case netcli really is a pyhton script. Why did I have to wrap it in a shell script that looks like:
#!/bin/sh
# Helper script to set the path for netcli menu
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
exec /etc/netcli

When you run out of getty, you have a very restrictive shell. The python script called a bunch of other programs, so it needed to have a good path. Also, since the shell didn't need to stick around, I tossed the typical 'exec' at the end of it to save a little bit of memory on this embedded system.

And there you have it. All the steps to create a program that runs automatically at boot. If you have any other cool tricks, please feel free to comment here...

20110117

FreeBSD/mips for Cavium Octeon

I've recently improved the ABI selection in FreeBSD/mips. Now it is all handled via MACHINE_ARCH or TARGET_ARCH. mipsel and mipseb are the o32 32-bit versions. mips64eb and mips64el are for n64 64-bit versions.

I've knocked together a script for building an image for the Cavium Octeon eval boards that have CF that can boot using uboot from SDK 1.9.0 and 2.0.0 (and likely earlier versions, but I've not tested them). It creates two partitions: a FAT partition for the kernel and BSD partition for the rest of FreeBSD. It also takes care of building a big endian ufs system on a little endian system. You can find the script here. I've also create an image as well you can grab here. The script contains instructions for how to create the CF image.

Enjoy

20101202

New FreeNAS beta snapshot released (r5648)

We've released the next beta snapshot of FreeNAS.

You can read the release notes for all the details.

Here's a highlight of the issues that we've fixed since the last beta (r5606):
  • Upgrades from prior FreeNAS 8 beta releases are now supported.
  • zfs creation failures have been fixed. The gui would indicate it succeeded, but you couldn't share it.
  • ufs creation failures have been fixed.
  • booting off USB or SCSI cdrom is now supported.
  • Many disk initialization errors that showed up as odd failures have been corrected.
  • lagg has been introduced.
  • Errors in the network screen have been corrected.
  • The storage wizard no longer says 'of X' when creating the storage unit. This eliminates the confusing 1 of 3 -> 2 of 2 dialog heading.
  • Improved compatibility with IE and Safari.
  • The installer has been streamlined.
Also, I was pleasantly surprised today when I logged in and found 19 comments from my last blog entry. I'm not used to so many, so hadn't been checking. I'll be checking more here. I'll also write a blog entry to address many of the issues raised in them.


You can download the latest from sourceforge.