Homepage Johann Hanne 
Valid XHTML 1.0 Strict
About | Projects | Gadgets | Photos | Links
Projects - Actiontec DPCM stuff - Kernel patch history 
This page only has historic purposes. Most people interested in DPCM kernels want the DPCM kernels page.

Warning: Although I did test all these patches very carefully, they may not work for you. They may even kill your DPCM (no joke, some people on the actionhack mailing really broke their devices by flashing oversized images or wrong kernels). Installing firmware which wasn't made by Actiontec will also probably void your warranty. Please also note that I'm in no way affiliated to Actiontec. My work is based on code published by them, but the changes made to the linux kernel since version 2.4.6 (which is the version Actiontec is using) are huge.

This page describes how I got a current 2.4 uClinux kernel working with the Actiontec Dual PC modem. It wasn't an easy task as although I'm familiar with C I'm not a kernel hacker and never did anything at the kernel level. Most of the time I simply applied the kernel patches from kernel.org and tried to repair the rejects by hand. From time to time I synced up with the official uClinux releases always doing some rediffing again and again. And as if this weren't enough, I didn't even have a serial console. So after fixing the rejects, fixing the compile errors and fixing the linking errors I often flashed the new kernel image only to discover that something did not work...

Finally, after putting most of my spare time in that project for more than a month, I got a working 2.4.27 kernel. And I even got an IPSEC enabled kernel to work on the DPCM (with a 2.4 kernel that had a 2.6-IPSEC backport included), achieving a throughput of 200 kBit/s with 3DES encryption.

The project had four major steps:

  1. Drop as many of the differences between the official uClinux 2.4.6 kernel and the 2.4.6 kernel published by Actiontec as possible (it also included huge updates to non-armnommu architectures).
  2. Go all the way from 2.4.6 to 2.4.27 by applying and adjusting the official und uc-linux kernel patches.
  3. Drop any modifications to the uClinux-2.4.27 kernel which are not required to run it on the DPCM.
  4. Feed the patches into the official uClinux kernel tree.

Most interested people will go down to the bottom of the page to grab the latest patches so they can compile a kernel for their DPCM with all the options they want. The rest of the page is just some documentation on how I did it. Maybe somebody is interested in this stuff, too. Furthermore, this proves that I did not steal any SCO code :-).

Step 1: I diff'ed uClinux-2.4.6.0pre0.diff.gz and uClinux-2.4.6.0pre1.diff.gz against the Actiontec kernel which they published on their opensource site at http://opensource.actiontec.com/. While looking through the resulting diff file I noticed that large parts of the differences are absolutely unnecessary for running the kernel on the DPCM. Several thousands of the diff lines only involved changing the CVS fields ($Id, $Revision, etc.), which I filtered out by giving the according options to diff. Even larger parts were about changing files that belonged to other (i.e. non-armnommu) architectures. I dropped all this unrelated stuff and split the remaining changes into smaller files, putting together changes which I thought belong together. After doing diff's against uClinux-2.4.6.0pre0 and uClinux-2.4.6.0pre1 I noticed that the differences between the Actiontec kernel and pre1 are much smaller than between the Actiontec kernel and pre0. However, the Actiontec kernel itself contains version number 2.4.6.0pre0 in the top-level Makefile. This leads me to the following conclusion (a guess!): At some time (between the releases of 2.4.6.0pre and 2.4.6.0pre1), Conexant pulled a copy of the uClinux CVS and made it their internal tree which they worked on. Some of their changes were fed back into the official uClinux tree (arch/armnommu/mach-cx821xx and cnxtserial.* are included starting with uClinux-2.4.24-uc0). Other parts never got into the official tree, e.g. the cnxt_emac driver. On the other hand, Conexant seems to have backported some features of post-2.4.6 linux kernels into their tree. This is at least true for the ip_conntrack_irc module, which is present in the 2.4.6 kernel released by Actiontec but which was first included in linux-2.4.14 and uClinux-2.4.17-uc0.

Note that I tried not to change any code in the Actiontec kernel which would affect the resulting kernel image, i.e. not even a string. The reason for this is that I wanted to keep it possible to reproduce a kernel image which exactly matches the kernel image made by Actiontec. If we really have the complete source tree which was used by Actiontec, this would theoretically be possible. It's noteworthy that Actiontec never actually released their tree (GPL violation!). What they actually put on their website seems to be a tree which they received from Conexant. All the Actiontec/DPCM specific code is missing from it. The missing parts (which are included in my patch as 31_nonactiontec_lightner-1.3.diff) were posted by Bruce D. Lightner to the actionhack mailing list (he never revealed where he got the files from). Without his post, this project would not have been possible.

These are the patches for uClinux-2.4.6.0pre0 and uClinux-2.4.6.0pre1. The patches on the left side of the table are only required for uClinux-2.4.6.0pre0. The patches on the right side of the table are only required for uClinux-2.4.6.0pre1. The patches on the center are required for both uClinux trees. Please note that the files which are different for pre0 and pre1 have the same name, so if you want to get them both, put them into separate directories! As the middle aligned patches apply to both pre0 and pre1, they will sometimes only apply with offsets and fuzzes. This does not matter, as long as you don't get any rejects.

Patches for uClinux-2.4.6.0pre0/uClinux-2.4.6.0pre1
uClinux-2.4.6.0pre0 uClinux-2.4.6.0pre1
01_armnommu.diff 01_armnommu.diff
01_armnommu.tar.bz2 01_armnommu.tar.bz2
02_cx821xx.tar.bz2
03_proc_areainfo.diff
05_blkmem.diff
06_export_symbols.diff
07_inflate_fprintf_to_printk.diff
08_skbuff_prevent_printk_storms.diff
09_slab.diff
10_default_to_ipforwarding.diff
11_export_symbol_ldiscs.diff
20_misc.diff
21_exec.diff  
22_kcore.diff  
23_kcore.diff
24_bootmem.diff  
25_bootmem.diff
26_binfmt_flat.diff  
27_binfmt_flat.diff
30_nonactiontec_head-armv.S-fix.diff
31_nonactiontec_lightner-1.3.diff
32_nonactiontec_config.tar.bz2
66_ipc_remove_asmlinkage_dummyfunctions.diff
70_cnxt_serial.diff
70_cnxt_serial.tar.bz2
71_cnxt_serial.diff 71_cnxt_serial.diff
80_cnxt_emac.diff
80_cnxt_emac.tar.bz2
81_cnxt_emac_enable_tx_dma.diff
90_netfilter.diff
90_netfilter.tar.bz2

To get the complete kernel tree, first untar
http://www.kernel.org/pub/linux/kernel/v2.4/linux-2.4.6.tar.bz2
and than apply
http://www.uclinux.org/pub/uClinux/uClinux-2.4.x/uClinux-2.4.6.0pre0.diff.gz
or
http://www.uclinux.org/pub/uClinux/uClinux-2.4.x/uClinux-2.4.6.0pre1.diff.gz.
Then grab all the patches from the table above for either 2.4.6.0pre0 or 2.4.6.0pre1, depending on what uClinux patch you chose. Then do:

# cd /path/to/uClinux/kernel/tree
# for f in /path/to/patches/*.tar.bz2; do tar xjvf $f; done
# cat /path/to/patches/*.diff | patch -p1
# make ARCH="armnommu" CROSS_COMPILE="arm-elf-" oldconfig
# make ARCH="armnommu" CROSS_COMPILE="arm-elf-" dep
# make ARCH="armnommu" CROSS_COMPILE="arm-elf-" linux.bin
# gzip <linux.bin >linuz

If you apply these patches on top of a vanilla 2.4.6 kernel + uClinux 2.4.6.0preX, the parts of the resulting kernel tree which are used for the DPCM will generally match the combination of the Actiontec/Conexant 2.4.6 kernel release (uClinux-cnxt-35052.006-2.tar.gz) + BDL's DPCM GPL patch (DualPcModemGplPatch_1.3.tar.gz). If you want to check this, it is possible to produce a binary equal linux.bin from both trees, if you adhere to some instructions:

  • It only works for the 2.4.6.0pre0 patchset.
  • You must compile both kernels from the same directory. This is because the kernel image will contain the filenames of some source files with the complete path.
  • You must use the same kernel config file (.config) of course. The BDL tarball has its own version, but the version above (32_nonactiontec_config.tar.bz2) should be much closer to the one used by Actiontec.
  • Remove the "$(EXTRAVERSION)" portion at the end of the "KERNELRELEASE=..." line in the Makefile as the Actiontec/Conexant kernel source doesn't include it either.
  • You must apply 34_make_binary_equal_to_lightner_patchset.diff on top of my patchset. This patch makes some whitespace changes which will result in a different kernel image for some reason (I have no idea why!). It also moves "EXPORT_SYMBOL(ldiscs);" from drivers/char/tty_io.c to arch/armnommu/kernel/armksyms.c. The BDL sources have it in arch/armnommu/kernel/armksyms.c, but from comparing binary kernel images I know that the original Actiontec sources have it in drivers/char/tty_io.c.
  • You must not apply 81_cnxt_emac_enable_tx_dma.diff from my patchset. This enables TX DMA for the ethernet ports. I know that this is enabled in the original Actiontec kernel, because the binary kernel image from Actiontec includes a text string which is inside a "#ifdef TX_DMA_INT" block. However it is not enabled in the cnxt_emac driver from the Actiontec/Conexant kernel source release.
  • You must apply the 33_fakeversion.diff patch for both trees. This is because kernel images always include a compile timestamp. So kernel images compiled from the same sources at different times will always differ without this patch.
  • You must apply the 30_nonactiontec_head-armv.S-fix.diff patch to either none or both kernel trees. It fixes a compile error which occurs with the toolchain I'm using. If you have an other toolchain, you might be able to leave this patch out, just be sure to leave it out for both trees then!

Step 2: After having the minimum set of patches for 2.4.6, I first tried to directly port them to 2.4.27-uc1, but this did not work. The kernel probably booted up to some point, but without a serial console, I didn't have a chance to see where it failed. So I tried to go step by step, by applying the patch to 2.4.7 first, then 2.4.8, and so on. All this was very painful, especially the step from 2.4.7 to 2.4.8 took me some time. But after I had 2.4.10, the steps got bigger from 2.4.10 over 2.4.17 and 2.4.20 to finally 2.4.27. As we have 2.4.27-uc1 now, the intermediate steps are quite useless. However, if somebody discovers a bug, they may be helpful to find out where the bug has been introduced. So here are the patches:

linux-2.4.7-tiburon.diff.bz2
linux-2.4.8-tiburon.diff.bz2
linux-2.4.9-tiburon.diff.bz2
linux-2.4.10-tiburon.diff.bz2
linux-2.4.10-uc0-tiburon.diff.bz2
linux-2.4.10-uc2-tiburon.diff.bz2
linux-2.4.17-uc0-tiburon.diff.bz2
linux-2.4.20-uc1-tiburon.diff.bz2
linux-2.4.27-uc1-tiburon.diff.bz2
linux-2.4.28-tiburon.diff.bz2

You need to use "patch -p2" for these patches!

The uc-based patches (i.e. the patches with "-uc" in their name) apply against the uClinux kernels (i.e. the vanilla kernel from kernel.org plus the uc patchset from uclinux.org). The other non-uc-based patches apply against the vanilla kernels from kernel.org. Every patch contains a config.working file that you can rename to .config and do the usual "make oldconfig && make dep && make linux.bin" procedure. Note: These patches are in no way made to represent the minimum of changes required to make the kernel work on the DPCM (in contrast to the 2.4.27 patches at the end of the page). Also, the config.working files do NOT include the features required to regularly use the DPCM, they only contain the minimum features to boot the modem and connect to it with telnet.

Step 3: After quite some time I finally had a working uClinux-2.4.27-uc1. As I very often copied files and functions from old kernels just to get a new kernel version working the differences to the official uClinux kernel were quite big. So I again used the try-and-error method and tried switching to the new kernel code bit for bit. A few days later I had nailed down the changes to a minimum (~500 kB context diff). I then split the patches up so the changes got clear. The following table shows the patches, with every patch having a single purpose. This makes understanding of the changes very easy. Although I have no experience with kernel level programming, I roughly know what each patch is doing. The exception are the binfmt_flat_workaround and the armnommu patch. The binfmt patch changes something which I don't understand at all, but the original DPCM binaries won't run without it (they will result in a SIGSEGV) - i guess it's a workaround for some other problem, maybe because the flat binaries are not 100% correct. I also haven't a clue about the armnommu patch - somebody with ARM knowledge has to tell me what this is all about. Luckily the DPCM will run without both these patches (but not with the original romdisk!), so I'll leave them out in the future. I only keep them on this page, so if someone discovers a problem with the new kernel, he can try to add these patches to see if they solve it.

Patches for uClinux-2.4.27-uc1
fix_cx821xx_exports-objs.diff
remove_min_max.diff
add_cnxt_inits.diff
add_tiburon_board.diff
blkmem_offset.diff
gpiob27.diff
add_cnxt_sysmem.diff
add_cnxt_emac_driver.diff
cnxtflash_update.diff
add_mtdcnxt.diff
cnxt_emac_enable_tx_dma.diff
add_mac_mutex_chk.diff
fixed_mac.diff
linkerscript.diff
export_symbols.diff
binfmt_flat_workaround.diff
ld_romfs.diff
armnommu.diff
makefile.diff
init_mmap.diff
nr_irqs.diff
mem_size.diff
add_linuz_target.diff

After analyzing the patches further, it's clear that some of the patches are not required:

  • add_linuz_target.diff: This is only for your convenience. It adds a target named "linuz" to the armnommu makefile. You can use "make linuz" to get the compressed image that the DPCM expects if you apply the patch. As it probably won't be accepted for the official uClinux tree, this patch will be dropped for future releases. Just issue the commands manually: "make linux; arm-elf-objcopy -O binary linux linux.bin; gzip <linux.bin >linuz".
  • mem_size.diff: It doesn't make any difference. "DRAM_SIZE" will result in the same number as "END_MEM-PAGE_OFFSET". Just have a look at include/asm-armnommu/arch-cx821xx/memory.h.
  • nr_irqs.diff: NR_IRQS probably is only the maximum number of IRQs. So the higher number won't hurt.
  • init_mmap.diff: The "init_mmap" variable that gets introduced here isn't used anywhere, so it can't be required.
  • makefile.diff: This is convenience stuff only. Instead of putting the ARCH and CROSS_COMPILE information in the Makefile, you can (and should) specify it at the command line: "ARCH=armnommu CROSS_COMPILE=arm-elf- make ...". "CONFIG_UCLINUX=y" is set automatically ("define_bool CONFIG_UCLINUX y" in arch/armnommu/config.in).
  • armnommu.diff: No idea here. The DPCM seems to work fine without these patches. Somebody with ARM knowledge has to tell me what they are doing and if they are required.
  • ld_romfs.diff: This patch adds a 800 kB section to the kernel image which could hold an initial filesystem, but this is not used for the DPCM. Don't use these two parts as this would waste 800 kB of RAM!
  • binfmt_flat_workaround.diff: Only required if you want to use the flat binaries which are inside the romfs published by Actiontec (as part of the DPCM firmware). If you don't apply this patch, the Actiontec binaries will result in a SIGSEGV and the kernel will throw an error message like "BINFMT_FLAT: reloc outside program 0xc0a20000 (0 - 0xaad4/0x8290), killing agetty!". Binaries compiled with the toolchain from the uclinux toolchain page will work without this patch. Therefore I think it must be a bug in the Actiontec binaries which make them work only on their old 2.4.6 kernel. It might be caused by the old elf2flt (elf2flt-20020208.tar.gz) they are using or by their compiler, which doesn't contain the patches which are in the official uclinux toolchain.
  • export_symbols.diff: Only required for the cnxtserial_buildin binary module. If you want to use this module, apply this patch.

Finally, I've created a working .config file which you can use as a starting point for you experiments. It includes all of the features which are in the original kernel (and in the 2.4.6 config file from above) except for:

  • CONFIG_BD_GOLDENGATE:
    The patches add a board named Tiburon which is the internal name for the DPCM at Actiontec. It enables all the required features, so the Goldengate config option should not be used.
  • CONFIG_SET_MEM_PARAM:
    No longer required as choosing the Tiburon board sets the RAM/flash parameters automatically (which are DRAM_BASE=0x00800000, DRAM_SIZE=0x00780000, FLASH_MEM_BASE=0x00400000, FLASH_SIZE=0x00200000).
  • CONFIG_NETLINK, CONFIG_RTNETLINK:
    Netlink is now always compiled in if network support is configured, i.e. no longer deselectable (see net/Makefile).
  • CONFIG_MTD_MTDRAM:
    The hacked up mtdram module has been replaced by the mtdcnxt module which uses CONFIG_MTD_MTDCNXT.
  • CONFIG_BLK_DEV_BLKMEM_ROM/CONFIG_BLK_DEV_BLKMEM_ROM_STATIC:
    No longer used by the kernel. The correct blkmem offset for the Tiburon (0x004b0000) is hardcoded in drivers/block/blkmem.c.
  • CONFIG_MSDOS_PARTITION:
    This makes absolutely no sense as we will never deal with MSDOS partition tables on the DPCM.
  • CONFIG_NO_FRAME_POINTER:
    No longer used by the kernel. Recent kernels use a config option named CONFIG_FRAME_POINTER, i.e. the logic is reversed. However, this option is fixed to "y" in arch/armnommu/config.in ("define_bool CONFIG_FRAME_POINTER y"). There must be a reason for it, so I've left it alone.

There are also some new features I've chosen to include additionally as they make sense to me:

  • CONFIG_BD_TIBURON:
    The newly introduced board support package which sets some configuration parameters for the DPCM.
  • CONFIG_CPU_WITH_CACHE, CONFIG_CPU_WITH_MCR_INSTRUCTION:
    CPU features automatically selected for the CX821xx in arch/armnommu/config.in.
  • CONFIG_REDUCED_MEMORY:
    We only have 8 MB RAM, so it's always good to try to save it. I have not checked if this really saves some bytes though.
  • CONFIG_IP_NF_H323, CONFIG_IP_NF_AMANDA, CONFIG_IP_NF_TFTP, CONFIG_IP_NF_IRC, CONFIG_IP_NF_CT_PROTO_GRE, CONFIG_IP_NF_PPTP, CONFIG_IP_NF_MATCH_IPRANGE, CONFIG_IP_NF_MATCH_PKTTYPE, CONFIG_IP_NF_MATCH_TOS, CONFIG_IP_NF_MATCH_TIME, CONFIG_IP_NF_MATCH_RECENT, CONFIG_IP_NF_MATCH_ECN, CONFIG_IP_NF_MATCH_DSCP, CONFIG_IP_NF_MATCH_AH_ESP, CONFIG_IP_NF_MATCH_LENGTH, CONFIG_IP_NF_MATCH_TTL, CONFIG_IP_NF_MATCH_HELPER, CONFIG_IP_NF_MATCH_CONNTRACK, CONFIG_IP_NF_MATCH_STRING, CONFIG_IP_NF_TARGET_NETMAP, CONFIG_IP_NF_NAT_H323, CONFIG_IP_NF_NAT_AMANDA, CONFIG_IP_NF_NAT_IRC, CONFIG_IP_NF_NAT_PPTP, CONFIG_IP_NF_NAT_PROTO_GRE, CONFIG_IP_NF_NAT_TFTP, CONFIG_IP_NF_TARGET_TOS, CONFIG_IP_NF_TARGET_ECN, CONFIG_IP_NF_TARGET_DSCP, CONFIG_IP_NF_TARGET_IMQ:
    As the DPCM is a network box, it's always good to have all the netfilter options. However, it may be a good idea to check if this creates some performance penalties. If yes, they should either be compiled as module (which will waste some bytes in the romfs) or disabled again.
  • CONFIG_PPP_DEFLATE, CONFIG_PPP_BSDCOMP:
    Include the PPP compression algorithms. They may be useful if you use the 56k modem.
  • CONFIG_PPPOE:
    As the DPCM has two ethernet interfaces, you can use one of them for PPPoE of course.
  • CONFIG_MTD_MTDCNXT:
    mtdcnxt is the replacement for the hacked up mtdram driver.
  • CONFIG_NOFLASH:
    There is an option for choosing either Intel or AMD flash for the blkmem driver. My DPCM has an Intel chip, but I know there are also units that have a SST chip, so I chose not to choose either. This is probably only for flash write access which we don't use in conjunction with the blkmem flash area.
  • CONFIG_RAMFS:
    The shipped DPCM firmware uses a 256k chunk of RAM with an ext2 filesystem as ram disk. It seems much saner to me to use ramfs instead. I don't know why Actiontec didn't also choose ramfs, maybe because it can't limit the amount of RAM which is used.
  • CONFIG_FRAME_POINTER:
    See the section about CONFIG_NO_FRAME_POINTER in the dropped config options section above.
  • CONFIG_CONTIGUOUS_PAGE_ALLOC:
    A non-power-of-2-allocator which allows us to use the RAM more efficiently. This has not been available for 2.4.6.
  • CONFIG_MEM_MAP:
    Provides a visual representation about the used RAM at /proc/mem_map. Very nice to see where all the RAM goes.
  • CONFIG_ZLIB_INFLATE, CONFIG_ZLIB_DEFLATE:
    Not deselectable and probably required for the compressed FLAT binary format.

Step 4: This has been easier than I first thought. But as the above patches have been created very carefully they were accepted very quickly. As of 2005-03-30 all the patches have been applied to the official uClinux kernel tree. There has been one more patch not listed above which updates the cx821xx architecture. I have not tested if it will apply against uClinux-2.4.27-uc1, it's only here for the sake of completeness.