[syslinux] Boot from CD -> system + data on USB storage

Marc Haisenko haisenko at webport.de
Fri Nov 12 07:35:10 PST 2004


On Friday 12 November 2004 10:48, you wrote:
> Hi,
> I am looking for a solution to boot MY system on any PC.
>
> To store most of the system and all of my data I want to use an USB
> storage (in my case an external USB harddisk (2.0 capable)).
> Since booting off an USB device is not an universal thing I would prefer
> to have a boot disk with a minimal system - just enough to load most
> (all?) of the system from the attached USB device.
>
> Is this an easy thing - are there ready to use solutions out there?
>
> Thanks in advance.

Problem is the USB part...  ISOLINUX does not know a thing about USB, AFAIK, 
as it would require some drivers to do so (the BIOS does some tricks to boot 
from USB, IIRC).

You could do the following: have ISOLINUX, a kernel and an initrd on the CD 
and the rest of the system on USB. The kernel could either have USB support 
built in or have initrd load the modules. The initrd then searches all SCSI 
partitions for your root partition (e.g. by having a file "this_is_my_root" 
on that partition, and the initrd searches for a partition that has this file 
on it). When you've found the partition you set the device number 
in /proc/sys/kernel/real-root-dev.

I've written such an linuxrc in assembler that does just this for IDE. It 
probes all IDE partitions until it finds one that has a "/sbin/init" on it 
and then sets real-root-dev accordingly. I've attached the source. You 
need /dev/console and /dev/hd* to be in the initrd as well and an empty 
directory /proc.  My source is surely not very efficient but you should be 
able to adapt it easily (you only need to change the strings at the top of 
the source).

Problem is that if you want to upgrade your kernel you have to burn another 
CD.

C'ya,
	Marc

-- 
Marc Haisenko
Systemspezialist
Webport IT-Services GmbH
mailto: haisenko at webport.de
-------------- next part --------------
##############################################
# linuxrc-probeide                           #
#                                            #
# This is a special linuxrc implementation   #
# for initrd's, which tries to find file-    #
# systems that we can boot from (that is,    #
# that have a /sbin/init file).              #
#                                            #
# This program first mounts /proc and then   #
# tries to mount every IDE disk and their    #
# partitions until it finds a filesystem     #
# that has a /sbin/init file.                #
#                                            #
# It then writes the device number into the  #
# /proc/sys/kernel/real-root-dev file which  #
# tells the Linux kernel from which device   #
# to boot from.                              #
##############################################
# (C) 2004 Marc Haisenko <marc at darkdust.net> #
##############################################

.section .data

mountsource:	.asciz "none"
mountpoint:	.asciz "/proc"
mountpoint2:	.asciz "/mnt"
mountfstype:	.asciz "proc"

mountfstypeext3:	.asciz "ext3"
mountfstypeext2:	.asciz "ext2"
mountfstypereiserfs:	.asciz "reiserfs"

mountfslist:	.long 0
		.long 0
		.long 0
		.long 0

mountoptions:	.long 0
stringdisk:	.asciz "disk"
errormount:	.asciz "Couldn't mount /proc: "


stringfound:	.asciz "Found harddisk: "
stringnothd:	.asciz "Not a harddisk: "
stringtesting:	.asciz "Trying to mount "
stringmounted:	.asciz "Successfully mounted "
stringisrootfs:	.asciz " is a potential root filesystem !\n"
stringnotrootfs:	.asciz " is not a potential root filesystem.\n"
stringcouldntwrite:	.asciz "Couldn't write device node nr. into real_root_dev file !\n"
stringsuccess:	.asciz "Successfully wrote into real_root_dev.\n"

realrootdevfile:	.asciz "/proc/sys/kernel/real-root-dev"

idefile:	.ascii "/proc/ide/hd"
idefilechar:	.ascii "a"
		.asciz "/media"
idedevice:	.ascii "/dev/hd"
idedevicechar:	.ascii "a"
idedevicepartition: .byte 0,0


buffer:		.long 0,0,0,0,0,0,0,0,0

current:	.long 0
currentdevice:	.long 0
currentdevicepartition:	.long 0
finaldevice:	.long 0

rootfsfile:	.asciz "/mnt/sbin/init"	# file which identifies a filesystem as a potential root filesystem



.section .text
        .globl _start
        .align 4

_start:
    movl $mountfstypeext3, (mountfslist)	# set up the filesystem list
    movl $mountfstypeext2, (mountfslist + 4)
    movl $mountfstypereiserfs, (mountfslist + 8)

    movl $mountsource, %ebx	# mount the proc filesystem
    movl $mountpoint, %ecx
    movl $mountfstype, %edx
    movl $0xc0ed0000, %esi
    movl $mountoptions, %edi
    movl $21, %eax	# syscall mount
    int  $0x80
    
    cmp  $0, %eax	# no error ?
    jz   _probehds	# yeah, so check for hda

    pushl %eax		# save error number
			# unhandled error numbers
    movl $2, (common_print_fd)	# print to stderr
    movl $errormount, %eax	# print mounterror string
    call print_cstring
    
    popl %eax		# restore error number
    call print_signed_number	# print error number
    call print_newline	# and a newline as well
    jmp  _exit1		# exit 1
    

_exit:
    movl $mountpoint, %ebx	# unmount /proc
    movl $22, %eax	# syscall umount
    int  $0x80
    
    xorl %ebx, %ebx	# exit 0
    movl $1, %eax
    int  $0x80

_exit1:
    movl $mountpoint, %ebx	# unmount /proc
    movl $22, %eax	# syscall umount
    int  $0x80
    
    movl $1, %ebx	# exit 1
    movl $1, %eax
    int  $0x80





### probehds
#
# The main routine
#
_probehds:

_probeide:
    movb (idedevicechar), %al	# which device are we currently probing ?
    cmp  $105, %al		# if we reached hdi we can stop (since that would be the master of the fifth channel !)
    je   _exit1
    
    movl $idefile, (current)
    movl $idedevice, (currentdevice)
    movl $idedevicepartition, (currentdevicepartition)
    
    movl (currentdevicepartition), %eax
    movl $0, (%eax)
    
    call _checkide
    
    test %eax, %eax		# check whether we found a root filesystem
    jz   _probeide_writerootfs	# we found one, write it into /proc/sys/kernel/real_root_dev

    movb (idedevicechar), %al	# get current device char
    incb %al			# increase current device char
    movb %al, (idedevicechar)	# write it back
    movb (idefilechar), %al	# same for the file string
    incb %al
    movb %al, (idefilechar)
    movb $0, (idedevicepartition)	# also clear the partition character
    
    jmp  _probeide		# loop

_probeide_writerootfs:
    movl (currentdevice), %ebx	# get device node nr. of the current device file
    movl $buffer, %ecx
    movl $106, %eax		# syscall stat
    int  $0x80
    
    movl (buffer), %eax		# print device node nr.
    call print_unsigned_number
    call print_newline
    
    movl $realrootdevfile, %ebx	# open /proc/sys/kernel/real_root_dev
    movl $0101, %ecx		# O_WRONLY | O_CREAT
    movl $0644, %edx		# -rw-r--r--
    movl $5, %eax		# syscall open
    int  $0x80
    
    test %eax, %eax		# successful opened ?
    js   _probeide_couldntwrite	# no, say so and exit
    
    movl %eax, (common_print_fd)	# print calls now write to that file
    movl (buffer), %eax		# print device node nr.
    call print_unsigned_number
    call print_newline
    
    movl $1, (common_print_fd)	# print to stdout again
    
    movl (buffer), %ebx		# close file
    movl $6, %eax		# syscall close
    int  $0x80
    
    movl $stringsuccess, %eax	# print that we were successful
    call print_cstring
    
    jmp  _exit
    
_probeide_couldntwrite:
    movl $stringcouldntwrite, %eax	# print that we couldn't write the device nr.
    call print_cstring
    jmp  _exit1



### checkide
#
# Check an IDE disk
#
_checkide:
    pushl %ebx		# save registers
    pushl %ecx
    pushl %edx
    
    movl (current), %ebx	# open /proc/ide/*/media
    xorl %ecx, %ecx	# O_RDONLY
    movl $5, %eax	# syscall open
    int  $0x80
    
    test %eax, %eax	# check return value
    js   _checkide1	# file not found, return
    
    movl %eax, %ebx	# now read the opened file to whether it's a disk or cdrom
    movl $buffer, %ecx	# read into buffer
    movl $4, %edx	# the string "disk" is 4 bytes long
    movl $3, %eax	# syscall read
    int  $0x80
    
    test %eax, %eax	# check return value
    js   _checkide2
    
    movl $buffer, %eax	# compare the read string with "disk"
    movl $stringdisk, %ebx
    call compare_cstring
    
    test %eax, %eax	# check return value
    jnz  _checkide1	# the read string is not "disk"

    call _print_diskfound    
    call _mountcheck	# try to mount and check for /etc
    
    popl %edx		# restore registers
    popl %ecx
    popl %ebx
    ret

_checkide1:
    call _print_nothd
    
    movl $-1, %eax	# no success
    popl %edx		# restore registers
    popl %ecx
    popl %ebx
    ret
        
_checkide2:
    movl %eax, %ebx	# move fd into ebx
    movl $6, %eax	# syscall close
    int  $0x80
    jmp  _checkide1


### print_diskfound
#
# Prints which device we're currently probing
#
_print_diskfound:
    pusha
    movl $stringfound, %eax
    call print_cstring
    
    movl (currentdevice), %eax
    call print_cstring
    call print_newline

    popa
    ret

### print_nothd
#
# Prints that the device was not found or is not a hd
#
_print_nothd:
    pusha
    movl $stringnothd, %eax
    call print_cstring
    
    movl (currentdevice), %eax
    call print_cstring
    call print_newline

    popa
    ret


### print_testing
#
# Prints which device we're currently trying to mount
#
_print_testing:
    pusha
    movl $stringtesting, %eax
    call print_cstring
    
    movl (currentdevice), %eax
    call print_cstring
    call print_newline

    popa
    ret

### print_mounted
#
# Prints which device we've successfully mounted
#
_print_mounted:
    pusha
    movl $stringmounted, %eax
    call print_cstring
    
    movl (currentdevice), %eax
    call print_cstring
    call print_newline

    popa
    ret

### print_isrootfs
#
# Prints that the current device is a root filesystem
#
_print_isrootfs:
    pusha
    movl (currentdevice), %eax
    call print_cstring
    
    movl $stringisrootfs, %eax
    call print_cstring

    popa
    ret

### print_notrootfs
#
# Prints that the current device is a not root filesystem
#
_print_notrootfs:
    pusha
    movl (currentdevice), %eax
    call print_cstring
    
    movl $stringnotrootfs, %eax
    call print_cstring

    popa
    ret


### mountcheck
#
# Try to mount a device or a partition on the device
#
_mountcheck:

_mountcheck_mount:
    call _print_testing
    movl $mountfslist, %ecx
    
_mountcheck_mount2:
    movl (%ecx), %edx
    test %edx, %edx
    jz   _mountcheck_nextdevice	# no more filesystems left to check, try next device
    
    movl %esi, (buffer)
    movl %edi, (buffer+4)
    movl %ecx, (buffer+8)
    movl (currentdevice), %ebx	# mount source
    movl $mountpoint2, %ecx	# /mnt
    movl $0xce0d0000, %esi
    movl $mountoptions, %edi
    movl $21, %eax
    int  $0x80
    movl (buffer), %esi
    movl (buffer+4), %edi
    movl (buffer+8), %ecx

    test %eax, %eax		# did the mount call succeed ?
    js   _mountcheck_mount3	# no, try next filesystem
    
    call _print_mounted		# we successfully mounted a device
    
    call rootpartitioncheck	# check whether the device is a root device
    
    call unmount		# unmount the device again
    
    test %eax, %eax
    jnz  _mountcheck_mount3	# it's not a root device, try next filesystem
    
    ret

_mountcheck_mount3:
    addl $4, %ecx		# next filesystem string pointer
    jmp  _mountcheck_mount2	# loop
    
_mountcheck_nextdevice:
    movl (currentdevicepartition), %eax	# pointer to pointer
    movl (%eax), %ebx
    test %ebx, %ebx		# test whether we checked whole disk
    jz   _mountcheck_nextdevice1
    
    incl %ebx			# increase device number
    movl %ebx, (%eax)		# save current partition
    
    cmp  $58, %ebx		# we only want to check the first 9 partitions
    jnb  _mountcheck_exit1
    jmp  _mountcheck_mount	# try next partition
    
_mountcheck_nextdevice1:
    movl $49, (%eax)		# use ASCII '1' as partition number
    jmp  _mountcheck_mount

_mountcheck_exit1:
    movl $-1, %eax
    ret


### unmount
#
# Unmount the mounted device
#
unmount:
    pusha			# save registers
    
    movl $mountpoint2, %ebx	# unmount /mnt
    movl $22, %eax		# syscall umount
    int  $0x80
    
    popa			# restore registers
    ret


### rootpartitioncheck
#
# Check whether the mounted filesystem could serve as a root filesystem
#
rootpartitioncheck:
    pushl %ebx			# save registers
    pushl %ecx
    pushl %edx
    
    movl $rootfsfile, %ebx	# check whether we find this file
    xorl %ecx, %ecx		# O_RDONLY
    movl $5, %eax		# syscall open
    int  $0x80

    test %eax, %eax		# check whether we could open that file
    js   _rootpartitioncheck1

    movl %eax, %ebx		# close file again
    movl $6, %eax		# syscall close
    int  $0x80
    
    call _print_isrootfs
    
    xorl %eax, %eax		# yes, it's a rootfs !
    
    popl %edx			# restore registers
    popl %ecx
    popl %ebx
    ret				# return to caller

_rootpartitioncheck1:
    call _print_notrootfs
    
    movl $-1, %eax		# it's not a roofs
    
    popl %edx			# restore registers
    popl %ecx
    popl %ebx
    ret				# return to caller


More information about the Syslinux mailing list