7

I'm working on an embedded ARM Linux system that boots using initramfs. (Here's some background from a couple earlier questions, if you're interested.) So far, thanks in part to help received here, I can boot the kernel via TFTP with an embedded initramfs. The MMC driver detects an SD card containing a new root filesystem, which I can then mount. However, I cannot get the final step, using busybox switch_root to switch to the filesystem on the SD card, to work.

At the initramfs shell prompt, I think this should make the kernel switch to the new filesystem:

switch_root -c /dev/console /mnt/root /sbin/init.sysvinit 

However, it just makes busybox (to which switch_root is aliased) print its man page, like this:

/ # switch_root -c /dev/console /mnt/root /sbin/init.sysvinit 
BusyBox v1.17.4 (2010-12-08 17:01:07 EST) multi-call binary.

Usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGS]

Free initramfs and switch to another root fs:
chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,
execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.

Options:

-c DEV  Reopen stdio to DEV after switch

I think the -c option is correct, since it's the same as what is contained in the example, and /dev/console exists.

/ # ls -l /dev
total 0
crw-r--r--    1 0        0           5,   1 Jan  1 00:28 console
brw-r--r--    1 0        0           7,   0 Dec 21  2010 loop0
brw-r--r--    1 0        0         179,   0 Dec 21  2010 mmcblk0
brw-r--r--    1 0        0         179,   1 Dec 21  2010 mmcblk0p1
brw-r--r--    1 0        0         179,   2 Dec 21  2010 mmcblk0p2
brw-r--r--    1 0        0         179,   3 Dec 21  2010 mmcblk0p3
brw-r--r--    1 0        0         179,   4 Dec 21  2010 mmcblk0p4

/mnt/root also exists.

/ # ls /mnt/root
bin         etc         linuxrc     mnt         sys         var
boot        home        lost+found  proc        tmp
dev         lib         media       sbin        usr

The init executable exists:

/ # ls -lh /mnt/root/sbin/
<snip>
lrwxrwxrwx    1 0        0             19 Dec 21  2010 init -> /sbin/init.sysvinit
-rwxr-xr-x    1 0        0          22.8K Dec 21  2010 init.sysvinit

But here's something strange:

/mnt/root/sbin # pwd
/mnt/root/sbin
/mnt/root/sbin # ls -l | grep init.sysvinit
lrwxrwxrwx    1 0        0               19 Dec 21  2010 init -> /sbin/init.sysvinit
-rwxr-xr-x    1 0        0            23364 Dec 21  2010 init.sysvinit
/mnt/root/sbin # ./init.sysvinit 
/bin/sh: ./init.sysvinit: not found
/mnt/root/sbin # /mnt/root/sbin/init.sysvinit 
/bin/sh: /mnt/root/sbin/init.sysvinit: not found

That's totally mystifying. I'm not sure where I'm going wrong. I've looked at the source, which is at http://git.busybox.net/busybox/tree/util-linux/switch_root.c?id=1_17_4

It's not just the init.sysvinit executable. I can't execute anything from the SD card. For example:

/mnt/root/bin # ./busybox 
/bin/sh: ./busybox: not found
/mnt/root/bin # /mnt/root/busybox 
/bin/sh: /mnt/root/busybox: not found
/mnt/root/bin # ls -l | grep "2010 busybox"
-rwxr-xr-x    1 0        0           462028 Dec 21  2010 busybox

Anyone have a clue what's amiss here? I thought it might be some problem with mounting the card noexec, but I believe exec is the default, and I tried passing the exec option explicitly at mount with no success.

2 Answers 2

15

The reason that switch_root is not working on the command line is this code in busybox:

    if (st.st_dev == rootdev || getpid() != 1) {
        // Show usage, it says new root must be a mountpoint
        // and we must be PID 1
        bb_show_usage();
    }

You are not PID 1, so you are falling through into this bb_show_usage. The implication is that the switch_root command in your initramfs init script should run switch_root with exec. i.e.

exec switch_root ...

The other issue with your "not found" errors is likely because the shared libraries needed by the executables are not found, because the initramfs root filesystem does not have them. If you can get switch_root to work with exec, then is likely the "not found" error will go away.

1
  • Jackpot-- that worked exactly right. There was one other problem I had to solve (MMC driver needing a longer timeout) that kept it from working when I tried this previously, but with that fixed, it worked beautifully. Thanks.
    – pingswept
    Commented Dec 21, 2010 at 6:43
1

switch_root -c /dev/console /mnt/root /mnt/root/sbin/init.sysvinit worked for me. I had the same problem but switch_root -c /dev/console /mnt/root /sbin/init.sysvinit did not work.

Am sorry None worked for me.

I made a ext2 file system copied statically built busybox with all its softlinks. And busybox has sticky bit.(-rwsr-sr-x permissions). I have a /linuxrc and i dont have much in the /etc/ directory. And i make image from the ext2 filesystem with the following command.

mkimage -C gzip -A ppc -O linux -T ramdisk -a 0x2000000 -n "ramdisk" -d initrd-ext2 initrd.img

I keep the initrd.img as a seperate file in /boot/ and is not part of kernel.

The contents of linuxrc are

#!/bin/sh (Also tried #!/bin/busybox sh)

mkdir -p /proc /dev /sys /mnt /tmp
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mknod /dev/misc/rtc0 c 254 0
mdev -s
mkdir -p /new_root
mount /dev/mmcblk0p2 /new_root
exec switch_root -c /dev/console /new_root /sbin/init

My kernel gets loaded properly and the initrd.img also gets loaded and the linuxrc gets executed but at the end switch_root gives usage help.

But then the my system continues to boot and loads the new rootfs. The following is the sequence.

RAMDISK: ext2 filesystem found at block 0
RAMDISK: Loading 10240KiB [1 disk] into ram disk... done.
VFS: Mounted root (ext2 filesystem) on device 1:0.
Starting initramfs boot...

Waiting 5 seconds for devices to settle...

kjournald starting.  Commit interval 5 seconds
EXT3 FS on mmcblk0p2, internal journal
EXT3-fs: mounted filesystem with writeback data mode.
BusyBox v1.21.0.git (2012-10-17 00:34:21 PDT) multi-call binary.

Usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGS]

Free initramfs and switch to another root fs:
chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,
execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.

        -c DEV  Reopen stdio to DEV after switch

VFS: Mounted root (ext3 filesystem) on device 179:2.
Trying to move old root to /initrd ... /initrd does not exist. Ignored.
Unmounting old root
Trying to free ramdisk memory ... okay
Freeing unused kernel memory: 200k init
INIT: version 2.86 booting
Please wait: booting...
mount: sysfs already mounted or /sys busy
mount: according to mtab, sysfs is already mounted on /sys
Starting udev
udev: starting version 154
Root filesystem already rw, not remounting
Caching udev devnodes
  1. Is my ram freed after exiting the initrd.img in the above sequence?

  2. What if i do not do switch_root at the end of linuxrc and just put an exit? Wont that free up my ram from my old initrd img.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .