[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: RFC untested patch to boot an iso image file from Gujin signature (ia32)



> > > The Gujin bootloader can simulate an El-Torito boot process (creating
> > > a virtual BIOS disk with 2kbytes sectors) from an iso file image in a
> > > E2/3/4FS or FAT filesystem (instead of a real CDROM).
> > [...]
> >
> > > What are you thinking of this approach?
> >
> > sounds interesting. i'll sure give it a try and merge things after
> > squeeze (in about a week or two).
>
> Thanks, then I'll do some modifications (the -rc2 seem to not understand
> shell construct like "return $([ "${A}" != "${B}" ])", trivial to fix)
> and add CDROM probing (they are not included in /proc/partitions) to
> find iso image files inside ISO9660 filesystem on a CDROM, do more
> tests and resubmit within two weeks.

Here is what I have up-to now, I am not planning to add more things.
The function gujin_disk_source_file() will display the iso file when
that iso file was booted with Gujin (noemul selection), tested on rc2
(in the shell after the failure to locate the CDROM).
That function parameter (if present) is the mount point if the FS
needs mounting.
I am far to be sure the attached patch calls that function at the
right place, because my tries do not work - but I do not know
exactly how all is supposed to work.
The is three TODO comments, I am not sure they are important.
Any question, please ask!

Regards,
Etienne.

diff -ur squashfs-root-old/usr/share/initramfs-tools/scripts/live squashfs-root/usr/share/initramfs-tools/scripts/live
--- squashfs-root-old/usr/share/initramfs-tools/scripts/live	2010-12-24 17:55:50.000000000 +0000
+++ squashfs-root/usr/share/initramfs-tools/scripts/live	2011-02-08 18:50:52.112427717 +0000
@@ -1547,6 +1547,696 @@
 	return 1
 }
 
+# Helper functions to access the Gujin bootloader extended "$INT13SF"
+# signature in real-mode memory (kept unmodified by Linux), containing
+# the description of the El-Torito BIOS disk simulation source file.
+# Gujin solution do not search for a *.iso filename on every filesystem,
+# the signature identify the right partition.
+
+# printf to the current tty or to a file,
+# never mess with "return values" on standard output:
+debug()
+{
+#	printf "$@" >> /tmp/gujin.log
+#	printf "$@" > /dev/null
+#	printf "$@" > /dev/tty
+#	printf "$@" 1>&2
+	printf "$@" >> /live.log
+}
+
+# return/display the value of /dev/mem or stdin:
+peek()
+{
+	# parameters:
+	local OFFSET LENGTH FORMAT FILE
+	OFFSET=${1}
+	LENGTH=${2}
+	FORMAT=${3}
+	FILE=${4}
+
+	hexdump -v -n ${LENGTH} -s ${OFFSET} -e "${FORMAT}" ${FILE}
+}
+
+# return/display the decimal value of the byte:
+peekb()
+{
+	# parameters:
+	local OFFSET FILE
+	OFFSET=${1}
+	FILE=${2}
+
+	peek ${OFFSET} 1 '"%u"' ${FILE}
+}
+
+# return/display the decimal value of the 16 bits word
+peekw()
+{
+	# parameters:
+	local OFFSET FILE
+	OFFSET=${1}
+	FILE=${2}
+
+	peek ${OFFSET} 2 '"%u"' ${FILE}
+}
+
+# return/display the decimal value of the 32 bits word
+peekl()
+{
+	# parameters:
+	local OFFSET FILE
+	OFFSET=${1}
+	FILE=${2}
+
+	peek ${OFFSET} 4 '"%u"' ${FILE}
+}
+
+# return/display the hexadecimal value string of the 64 bits word
+peekll()
+{
+	# parameters:
+	local OFFSET FILE
+	OFFSET=${1}
+	FILE=${2}
+
+	peek ${OFFSET} 8 '/1 "%02X "' ${FILE}
+}
+
+# return/display the string of size ${LENGTH}
+peekstr()
+{
+	# parameters:
+	local OFFSET LENGTH FILE
+	OFFSET=${1}
+	LENGTH=${2}
+	FILE=${3}
+
+	peek ${OFFSET} ${LENGTH} '/1 "%c"' ${FILE}
+	# we could also:
+	#	dd bs=1 skip=$((${OFFSET})) count=$((${LENGTH})) \
+	#		${IF_FILE} 2>/dev/null
+}
+
+# Get the address of the TSR (Terminate & Stay Resident) managing BIOS disks:
+get_bios_irq_0x13()
+{
+	# NO parameters
+
+	local ADDR_IRQ13 OFFSET_IRQ13 SEGMENT_IRQ13 LINADR_IRQ13
+	# address of vector of BIOS disk services (0x13):
+	ADDR_IRQ13=$((4 * 0x13))
+	# address of BIOS disk services:
+	OFFSET_IRQ13=$(peekw ${ADDR_IRQ13} /dev/mem)
+	SEGMENT_IRQ13=$(peekw $((${ADDR_IRQ13} +2)) /dev/mem)
+	[ "${OFFSET_IRQ13}" = "" ] && return 1
+	LINADR_IRQ13=$((0x10 * ${SEGMENT_IRQ13} + ${OFFSET_IRQ13}))
+	debug "DISK IRQ at 0x%X:0x%X i.e. linear 0x%X\n" \
+		${SEGMENT_IRQ13} ${OFFSET_IRQ13} ${LINADR_IRQ13}
+	printf "%s" ${LINADR_IRQ13}
+	return 0
+}
+
+# Check if the TSR follows INT13SF format:
+# WEB search '$INT13SF' for detail of format
+check_INT13SF_signature()
+{
+	# parameters: TSR address
+	local LINADR_IRQ13
+	LINADR_IRQ13=${1}
+
+	local JMP0 JMP1 JMP2
+	JMP0=$(peekb $((${LINADR_IRQ13} +0)) /dev/mem)
+	JMP1=$(peekb $((${LINADR_IRQ13} +1)) /dev/mem)
+	JMP2=$(peekb $((${LINADR_IRQ13} +2)) /dev/mem)
+	debug "INT13SF jmp instruction: 0x%X 0x%X 0x%X\n" ${JMP0} ${JMP1} ${JMP2}
+
+	if [ ${JMP0} -eq $((0xe9)) -a ${JMP1} -eq $((0x89)) -a ${JMP2} -eq $((0x00)) ]
+	then
+		debug "Warning, maybe using old Gujin version, limited functionality\n"
+	fi
+
+	# test "Safe ID string":
+	local INT13SF_SIG INT13SF_CORRECT_SIG
+
+	INT13SF_SIG=$(peekll $((${LINADR_IRQ13} +3)) /dev/mem)
+	INT13SF_CORRECT_SIG=$(echo '$INT13SF' | peekll 0)
+	debug "INT13SF_CORRECT_SIG=%s, INT13SF_SIG=%s\n" \
+		"${INT13SF_CORRECT_SIG}" "${INT13SF_SIG}"
+
+	# display end of INT13SF structure:
+	debug "INT13SF oldintaddr 0x%X flags 0x%08X\n" \
+		$(peekl $((${LINADR_IRQ13} +3+8+8)) /dev/mem) \
+		$(peekl $((${LINADR_IRQ13} +3+8+8+4)) /dev/mem)
+
+	[ "${INT13SF_SIG}" != "${INT13SF_CORRECT_SIG}" ] && return 1
+	return 0
+}
+
+# Check if the TSR follows extended Gujin format:
+check_Gujin_signature()
+{
+	# parameters: TSR address
+	local LINADR_IRQ13
+	LINADR_IRQ13=${1}
+
+	# test "Vendor ID string":
+	local GUJIN_SIG GUJIN_CORRECT_SIG
+
+	GUJIN_SIG=$(peekll $((${LINADR_IRQ13} +3+8)) /dev/mem)
+	GUJIN_CORRECT_SIG=$(echo 'Gujin   ' | peekll 0)
+	debug "GUJIN_CORRECT_SIG=%s, GUJIN_SIG=%s\n" \
+		"${GUJIN_CORRECT_SIG}" "${GUJIN_SIG}"
+	[ "${GUJIN_SIG}" != "${GUJIN_CORRECT_SIG}" ] && return 1
+	return 0
+}
+
+# Try to locate the disk in use by using the disk serial number:
+# Only return (i.e. display) the path if a SINGLE disk match
+get_usb_disk_by_id()
+{
+	# parameters:
+	local EBIOS_DEVICE_ADR
+	EBIOS_DEVICE_ADR=${1}
+
+	debug "serial_number=0x%08X %08X %08X %08X\n" \
+		$(peekl $((${EBIOS_DEVICE_ADR} +0)) /dev/mem) \
+		$(peekl $((${EBIOS_DEVICE_ADR} +4)) /dev/mem) \
+		$(peekl $((${EBIOS_DEVICE_ADR} +8)) /dev/mem) \
+		$(peekl $((${EBIOS_DEVICE_ADR} +12)) /dev/mem)
+
+	# If there is only one single USB disk, that will be the one.
+	local PATTERN
+	PATTERN='/dev/disk/by-id/usb-*-0:0'
+	if [ $(ls -1 ${PATTERN} 2>/dev/null | wc -l) -eq 1 ]
+	then
+		debug "Single USB drive present: %s\n" ${PATTERN}
+		ls -1 ${PATTERN}
+		return 0
+	fi
+
+	# The only mapping on the serial number displayed by 'usb-devices'
+	# and present in /dev/disk/by-id/usb-*-0:0 and the one given by
+	# INT 0x13 AH=0x48 (WEB search D1386r5.pdf) which is named "64-bit
+	# Serial Number as defined in the USB Mass Storage specifications"
+	# which works for me is:
+	# TODO: Find why most disk do not follow that pattern, i.e. no
+	# relation in between those two serial numbers.
+	local DISK_BY_ID0 DISK_BY_ID1 DISK_BY_ID2
+	local DISK_BY_ID3 DISK_BY_ID4 DISK_BY_ID5
+
+	DISK_BY_ID0=$(peekb $((${EBIOS_DEVICE_ADR} +9)) /dev/mem)
+	DISK_BY_ID1=$(peekb $((${EBIOS_DEVICE_ADR} +8)) /dev/mem)
+	DISK_BY_ID2=$(peekb $((${EBIOS_DEVICE_ADR} +7)) /dev/mem)
+	DISK_BY_ID3=$(peekb $((${EBIOS_DEVICE_ADR} +6)) /dev/mem)
+	DISK_BY_ID4=$(peekb $((${EBIOS_DEVICE_ADR} +5)) /dev/mem)
+	DISK_BY_ID5=$(peekb $((${EBIOS_DEVICE_ADR} +4)) /dev/mem)
+	PATTERN=$(printf "/dev/disk/by-id/usb-*_%02X%02X%02X%02X%02X%02X-0:0" \
+		${DISK_BY_ID0} ${DISK_BY_ID1} ${DISK_BY_ID2} \
+		${DISK_BY_ID3} ${DISK_BY_ID4} ${DISK_BY_ID5})
+
+	debug "# searching ID: %s in 'ls /dev/disk/by-id/usb-*-0:0':\n" "${PATTERN}"
+	debug "# %s\n" $(ls -1 /dev/disk/by-id/usb-*-0:0)
+	if [ $(ls -1 ${PATTERN} 2>/dev/null | wc -l) -eq 1 ]
+	then
+		debug "Single USB drive with correct signature present\n"
+		ls -1 ${PATTERN}
+		return 0
+	fi
+	return 1
+}
+
+# Search in /dev/disk/by-path/pci-* if a block device correspond parameters:
+# Only return (i.e. display) the path if a SINGLE disk match
+find_usb_disk_by_path()
+{
+	# parameters:
+	local PCI_bus PCI_device PCI_function IS_SLAVE
+	PCI_bus=${1}
+	PCI_device=${2}
+	PCI_function=${3}
+	IS_SLAVE=${4}
+
+	local cpt_port list_port DISK_BY_PATH MATCH_FOUND
+
+	# search for directly connected, i.e. no HUB:
+	#	/dev/disk/by-path/pci-0000:00:12.1-usb-0:X:1.0-scsi-0:0:0:0
+	list_port="1 2 3 4 5 6 7 8"
+	# and search through first 8 USB HUB:
+	#	/dev/disk/by-path/pci-0000:00:12.1-usb-0:X.Y:1.0-scsi-0:0:0:0
+	# most USB HUB have only 4 ports:
+	list_port="${list_port} 1.1 1.2 1.3 1.4"
+	list_port="${list_port} 2.1 2.2 2.3 2.4"
+	list_port="${list_port} 3.1 3.2 3.3 3.4"
+	list_port="${list_port} 4.1 4.2 4.3 4.4"
+	list_port="${list_port} 5.1 5.2 5.3 5.4"
+	list_port="${list_port} 6.1 6.2 6.3 6.4"
+	list_port="${list_port} 7.1 7.2 7.3 7.4"
+	list_port="${list_port} 8.1 8.2 8.3 8.4"
+	MATCH_FOUND=0
+	for cpt_port in ${list_port}
+	do
+		DISK_BY_PATH=$(printf "/dev/disk/by-path/pci-%04x:%02x:%02x.%x-usb-0:%s:1.0-scsi-0:0:%u:0" \
+					0 ${PCI_bus} ${PCI_device} ${PCI_function} ${cpt_port} ${IS_SLAVE})
+		if [ -b "${DISK_BY_PATH}" ]
+		then
+			debug "Checking %s: is a block device\n" ${DISK_BY_PATH}
+			if [ ${MATCH_FOUND} != 0 ]
+			then
+				debug "Checking %s: we have 2 block device, abort\n" \
+					${DISK_BY_PATH}
+				return 1
+			fi
+			MATCH_FOUND=${DISK_BY_PATH}
+		else
+			debug "Checking %s: do not exist\n" ${DISK_BY_PATH}
+		fi
+	done
+	[ ${MATCH_FOUND} != 0 ] && printf "%s" ${MATCH_FOUND}
+	return 0
+}
+
+# Search in /dev/disk/by-path/pci* if a disk correspond to what
+# the BIOS said to Gujin:
+# TODO: fails if the wrong USB disk is on a main USB port,
+# and the right USB disk is on a USB HUB, loaded with OHCI.
+find_disk_by_path()
+{
+	# parameters:
+	local EBIOS_BUS_ADR EBIOS_INTERFACE IS_SLAVE IDE_BASE
+	EBIOS_BUS_ADR=${1}
+	EBIOS_INTERFACE=${2}
+	IS_SLAVE=${3}
+	IDE_BASE=${4}
+	
+	local PCI_bus PCI_device PCI_function DISK_BY_PATH
+
+	PCI_bus=$(peekb $((${EBIOS_BUS_ADR} +0)) /dev/mem)		# EBIOS_BUS[0]
+	PCI_device=$(peekb $((${EBIOS_BUS_ADR} +1)) /dev/mem)		# EBIOS_BUS[1]
+	PCI_function=$(peekb $((${EBIOS_BUS_ADR} +2)) /dev/mem)		# EBIOS_BUS[2]
+	debug "PCI_bus=0x%X, PCI_device=0x%X, PCI_function=0x%X\n" \
+		${PCI_bus} ${PCI_device} ${PCI_function}
+
+	# If PCI bus/device/function are not filled-in, search them from IDE_BASE
+	# in /proc/bus/pci/devices, and then scan /proc/bus/pci/ :
+	if [ "${PCI_bus}" -eq 0 -a "${PCI_device}" -eq 0 -a "${PCI_function}" -eq 0 -a "${IDE_BASE}" -ne 0 ]
+	then
+		local AWK_CMD PCI_NAME CPT_PCI
+		IDE_BASE=$(printf "%x" "${IDE_BASE}")
+		AWK_CMD="{ if ( \"${IDE_BASE}\" == \$4 || \"${IDE_BASE}\" == \$6 ) printf \"%s\" , \$2 ; }"
+		debug "%s\n" "AWK_CMD=${AWK_CMD}"
+		PCI_NAME=$(awk "$AWK_CMD" /proc/bus/pci/devices)
+		for CPT_PCI in /proc/bus/pci/*/*
+		do
+			local NAME
+			NAME=$(hexdump -n 4 -e '/2 "%04x"' ${CPT_PCI})
+			[ "${NAME}" = "${PCI_NAME}" ] && break
+			CPT_PCI="/proc/bus/pci/00/00.0"
+		done
+		CPT_PCI=${CPT_PCI#/proc/bus/pci/}
+		PCI_bus=${CPT_PCI%/*}
+		CPT_PCI=${CPT_PCI#${PCI_bus}/}
+		PCI_device=$((0x${CPT_PCI%.*}))
+		PCI_function=$((0x${CPT_PCI#*.}))
+		debug "From IDE_BASE %s: PCI_NAME %s; PCI_bus %s PCI_device %s PCI_function %s\n" \
+			"${IDE_BASE}" "${PCI_NAME}" "${PCI_bus}" "${PCI_device}" "${PCI_function}"
+	fi
+
+	if [ ${EBIOS_INTERFACE} = "USB" ]
+	then
+		DISK_BY_PATH=$(find_usb_disk_by_path ${PCI_bus} ${PCI_device} ${PCI_function} ${IS_SLAVE})
+		if [ ! -b "${DISK_BY_PATH}" -a $? -eq 0 ]
+		then
+			# happens when loaded with OHCI and Linux runs EHCI (USB disk on USB HUB):
+			# lspci: 00:12.1 USB Controller: ATI Technologies Inc SB700 USB OHCI1 Controller
+			#        00:12.2 USB Controller: ATI Technologies Inc SB700/SB800 USB EHCI Controller
+			if [ ${PCI_function} -eq 2 ]
+			then
+				PCI_function=1
+			else
+				PCI_function=2
+			fi
+			debug "try switching EHCI/OHCI, PCI_function=%u\n" ${PCI_function}
+			DISK_BY_PATH=$(find_usb_disk_by_path ${PCI_bus} ${PCI_device} ${PCI_function} ${IS_SLAVE})
+		fi
+	else
+		DISK_BY_PATH=$(printf "/dev/disk/by-path/pci-%04x:%02x:%02x.%x-scsi-0:0:%u:0" \
+			0 ${PCI_bus} ${PCI_device} ${PCI_function} ${IS_SLAVE})
+	fi
+	printf "%s" ${DISK_BY_PATH}
+}
+
+# Search each partition for the right start/length,
+# with ${DISK_BY_PATH_LINK} ${DISK_BY_ID_LINK} hints:
+# TODO: if two incompatible hints are given, decide
+# which one to ignore.
+find_device()
+{
+	# parameters:
+	local PARTITION_START PARTITION_LENGTH DISK_BY_PATH_LINK DISK_BY_ID_LINK
+	PARTITION_START=${1}
+	PARTITION_LENGTH=${2}
+	DISK_BY_PATH_LINK=${3}
+	DISK_BY_ID_LINK=${4}
+
+	local DEVICE_LIST CURPART CURDISK MATCH MATCHDISK EXTRA_EXCLUDE EXTRA_DEVICES
+	MATCH=0
+	MATCHDISK="none"
+
+	DEVICE_LIST=$(awk '/^ /{printf "%s ", $4}' /proc/partitions)
+	# Busybox 'ls' do not have -I
+	#EXTRA_EXCLUDE=$(printf -- "-I %s " ${DEVICE_LIST})
+	#EXTRA_DEVICES=$(ls -1 /sys/block -I loop[0-9] -I fd[0-9] -I ram[0-9]* ${EXTRA_EXCLUDE})
+	EXTRA_EXCLUDE=$(printf -- "/^%s/d;" ${DEVICE_LIST})
+	EXTRA_DEVICES=$(ls -1 /sys/block | sed "/^loop[0-9]/d;/^fd[0-9]/d;/^ram[0-9]*/d;${EXTRA_EXCLUDE}" | tr "\n" " ")
+
+	debug "EXTRA_EXCLUDE=${EXTRA_EXCLUDE}\n"
+	debug "EXTRA_DEVICES=${EXTRA_DEVICES}\n"
+
+	for CURPART in ${DEVICE_LIST} ${EXTRA_DEVICES}
+	do
+		unset CURDISK
+		if [ ! -d /sys/block/${CURPART} ]
+		then
+			# get "sda" from "sda2" AND get "mmcblk0" from "mmcblk0p1"
+			CURDISK=$(echo ${CURPART} \
+				| sed '/^mmcblk/s/p[0-9]*$//;/^mmcblk/!s/[0-9]*$//')
+			debug "%s is a partition of disk %s\n" ${CURPART} ${CURDISK}
+		fi
+
+		if [ "${CURDISK}" != "" ]
+		then
+			if [ "${DISK_BY_PATH_LINK}" != "" \
+				-a "${DISK_BY_PATH_LINK}" != ${CURDISK} ]
+			then
+				debug "%s is not part of the PCI disk %s\n" \
+					${CURDISK} ${DISK_BY_PATH_LINK}
+				continue
+			fi
+			if [ "${DISK_BY_ID_LINK}" != "" \
+				-a "${DISK_BY_ID_LINK}" != ${CURDISK} ]
+			then
+				debug "%s is not part of the ID disk %s\n" ${CURDISK} ${DISK_BY_ID_LINK}
+				continue
+			fi
+			if [ ${PARTITION_START} != $(cat /sys/block/${CURDISK}/${CURPART}/start) ]
+			then
+				debug "partition %s start %u wrong start\n" \
+					${CURPART} $(cat /sys/block/${CURDISK}/${CURPART}/start)
+				continue
+			fi
+			# Gujin <= v2.8.2 did not write fields PARTITION_LENGTH
+			# and PARTITION_TYPE, but easily recognised:
+			if [ ${PARTITION_LENGTH} != $(cat /sys/block/${CURDISK}/${CURPART}/size) \
+				-a ${PARTITION_LENGTH} != $((0xE0FA809C)) ]
+			then
+				debug "partition %s size %u wrong length\n" \
+					${CURPART} $(cat /sys/block/${CURDISK}/${CURPART}/size)
+				continue
+			fi
+			if [ ${MATCH} != 0 ]
+			then
+				debug "We have a double match %s (disk %s) and %s (disk %s), abort\n" \
+					${CURPART} ${CURDISK} ${MATCH} ${MATCHDISK}
+				return 1
+			fi
+			MATCH=${CURPART}
+			MATCHDISK=${CURDISK}
+			debug "## partition %s disk %s is one right device\n" \
+				${CURPART} ${CURDISK}
+		else
+			if [ "${DISK_BY_PATH_LINK}" != "" \
+				-a "${DISK_BY_PATH_LINK}" != ${CURPART} ]
+			then
+				debug "%s is not the PCI disk %s\n" \
+					${CURPART} ${DISK_BY_PATH_LINK}
+				continue
+			fi
+			if [ "${DISK_BY_ID_LINK}" != "" \
+				-a "${DISK_BY_ID_LINK}" != ${CURPART} ]
+			then
+				debug "%s is not the ID disk %s\n" ${CURPART} ${DISK_BY_ID_LINK}
+				continue
+			fi
+			if [ ${PARTITION_START} != 0 ]
+			then
+				debug "disk %s non null start\n" ${CURPART}
+				continue
+			fi
+			# We really need a /sys entry to know the sector size...
+			local SIZE_IN_512_SECTOR
+			SIZE_IN_512_SECTOR=PARTITION_LENGTH
+			if [ "${CURPART%%[0-9]}" = "sr" ]
+			then
+				SIZE_IN_512_SECTOR=$((4 * ${SIZE_IN_512_SECTOR}))
+				debug "disk name %s[0-9], compared size %u\n" "${CURPART%%[0-9]}" "${SIZE_IN_512_SECTOR}"
+			fi
+			# One USB disk give BIOS size 2007808 and linux size 2009088...
+			local DELTASIZE
+			DELTASIZE=$(( ${SIZE_IN_512_SECTOR} - $(cat /sys/block/${CURPART}/size) ))
+			[ ${DELTASIZE} -lt 0 ] && DELTASIZE=$((-${DELTASIZE}))
+			debug "abs(DELTASIZE)=%u\n" $DELTASIZE
+			# Gujin <= v2.8.2 did not write fields PARTITION_LENGTH
+			# and PARTITION_TYPE, but easily recognised.
+			if [ ${DELTASIZE} -gt 2048 \
+				-a ${PARTITION_LENGTH} -ne $((0xE0FA809C)) ]
+			then
+				debug "disk %s size %u wrong length\n" \
+					${CURPART} $(cat /sys/block/${CURPART}/size)
+				continue
+			fi
+			if [ ${MATCH} != 0 ]
+			then
+				debug "We have a double match %s and %s (disk %s), abort\n" \
+					${CURPART} ${MATCH} ${MATCHDISK}
+				return 1
+			fi
+			MATCH=${CURPART}
+			debug "## disk %s is one right device\n" ${CURPART}
+		fi
+	done
+	[ ${MATCH} != 0 ] && printf "%s" ${MATCH}
+}
+
+# Find the mount point (if already mounted) or create the mount directory
+# and mount the device (if MOUNT_POINT parameter not empty):
+find_create_mount_point()
+{
+	# parameters:
+	local THEDEVICE PARTITION_TYPE MOUNT_POINT
+	THEDEVICE=${1}
+	PARTITION_TYPE=${2}
+	MOUNT_POINT=${3}
+
+	local AWK_CMD THEMOUNTPOINT
+	# Do not expand following dollar, it is for awk:
+	AWK_CMD='{ print $2 }'
+
+	THEMOUNTPOINT=$(awk "/\/dev\/${THEDEVICE}/${AWK_CMD}" /proc/mounts)
+	if [ "${THEMOUNTPOINT}" = "" -a "${MOUNT_POINT}" != "" ]
+	then
+		# Set the default name there:
+		case ${PARTITION_TYPE} in
+			1) MOUNT_FS="iso9660" ;;
+			2) MOUNT_FS="ext4" ;;
+			3) MOUNT_FS="vfat" ;;
+			*) MOUNT_FS="auto" ;;
+		esac
+		if [ ! -d "${MOUNT_POINT}" ]
+		then
+			mkdir "${MOUNT_POINT}"
+		fi
+		mount -o ro -t ${MOUNT_FS} /dev/${THEDEVICE} ${MOUNT_POINT}
+		if [ $? -eq 0 ]
+		then
+			debug "Successfull mount %s on %s with type %s\n" \
+				/dev/${THEDEVICE} ${MOUNT_POINT} ${MOUNT_FS}
+		elif [ "${MOUNT_FS}" = "ext4" ]
+		then
+			mount -o ro -t ext3 /dev/${THEDEVICE} ${MOUNT_POINT}
+			if [ $? -eq 0 ]
+			then
+				debug "Successfull mount %s on %s with type ext3\n" \
+					/dev/${THEDEVICE} ${MOUNT_POINT}
+			else
+				mount -o ro -t ext2 /dev/${THEDEVICE} ${MOUNT_POINT}
+				if [ $? -eq 0 ]
+				then
+					debug "Successfull mount %s on %s with type ext2\n" \
+						/dev/${THEDEVICE} ${MOUNT_POINT}
+				else
+					debug "FAILED mount %s on %s with type ext4/ext3/ext2\n" \
+						/dev/${THEDEVICE} ${MOUNT_POINT}
+				fi
+			fi
+		else
+			debug "FAILED mount %s on %s with type %s\n" \
+				/dev/${THEDEVICE} ${MOUNT_POINT} ${MOUNT_FS}
+		fi
+		# Re-check:
+		THEMOUNTPOINT=$(awk "/\/dev\/${THEDEVICE}/${AWK_CMD}" /proc/mounts)
+	fi
+	printf "%s" ${THEMOUNTPOINT}
+}
+
+gujin_disk_source_file()
+{
+	# parameters:
+	local MOUNT_POINT
+	MOUNT_POINT=${1}
+
+	# computer information:
+	local LINADR_IRQ13 LINADR_GUJIN
+	# Data left in memory by Gujin:
+	local INT13FILENAME HOSTBIOS IDE_MASK IDE_BASE
+	local EBIOS_BUSTYPE EBIOS_INTERFACE
+	local PARTITION_START PARTITION_LENGTH PARTITION_TYPE
+	# Intermediate results we deduce:
+	local IS_SLAVE DISK_BY_ID DISK_BY_ID_LINK DISK_BY_PATH DISK_BY_PATH_LINK
+	# Final result:
+	local THEDEVICE THEMOUNTPOINT
+
+	if [ ! -r /dev/mem ]
+	then
+		debug "Cannot read /dev/mem, cannot continue!\n"
+		return 1
+	fi
+
+	LINADR_IRQ13=$(get_bios_irq_0x13)
+	if [ $? -ne 0 ]
+	then
+		debug "Either dd or hexdump abscent or not working!\n"
+		return 1
+	fi
+	
+	if ! check_INT13SF_signature ${LINADR_IRQ13}
+	then
+		debug "Not a TSR or do not conform to \$INT13SF standard\n"
+		return 1
+	fi
+
+	if ! check_Gujin_signature ${LINADR_IRQ13}
+	then
+		debug "TSR is not Gujin\n"
+		return 1
+	fi
+
+	# We now know that it is a Gujin disk simulation
+
+	# Following fields are only generated from the Gujin bootloader:
+	LINADR_GUJIN=$((${LINADR_IRQ13} +3+8+8+4+4))
+	debug "LINADR_GUJIN=0x%X INT13BIOSDISK=0x%X\n" \
+		${LINADR_GUJIN} $(peekb ${LINADR_GUJIN} /dev/mem)
+
+	INT13FILENAME=$(peekstr $((${LINADR_GUJIN} +1)) 64 /dev/mem)
+	HOSTBIOS=$(peekb $((${LINADR_GUJIN} +1+64)) /dev/mem)
+	IDE_MASK=$(peekb $((${LINADR_GUJIN} +1+64+1)) /dev/mem)
+	IDE_BASE=$(peekw $((${LINADR_GUJIN} +1+64+1+1)) /dev/mem)
+	debug "INT13FILENAME=%s, HOSTBIOS=0x%X, IDE_MASK=0x%X, IDE_BASE=0x%X\n" \
+		${INT13FILENAME} ${HOSTBIOS} ${IDE_MASK} ${IDE_BASE}
+
+	EBIOS_BUSTYPE=$(peekstr $((${LINADR_GUJIN} +1+64+1+1+2)) 4 /dev/mem)
+	EBIOS_INTERFACE=$(peekstr $((${LINADR_GUJIN} +1+64+1+1+2+4)) 8 /dev/mem)
+	debug "EBIOS_BUSTYPE=%s, EBIOS_INTERFACE=%s.\n" \
+		"${EBIOS_BUSTYPE}" "${EBIOS_INTERFACE}"
+	# Those are not strings:
+	#EBIOS_BUS=$(peekstr $((${LINADR_GUJIN} +1+64+1+1+2+4+8)) 8 /dev/mem)
+	#EBIOS_DEVICE=$(peekstr $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8)) 16 /dev/mem)
+	#debug "EBIOS_BUS=%s, EBIOS_DEVICE=%s\n" "${EBIOS_BUS}" "${EBIOS_DEVICE}"
+
+	# Warning: We will use ${EBIOS_INTERFACE} instead of "${EBIOS_INTERFACE}"
+	# to trim the trailing spaces, same for ${EBIOS_BUSTYPE}.
+	# We then cannot handle empty string:
+	if [ "${EBIOS_BUSTYPE}" = "" ]
+	then
+		EBIOS_BUSTYPE="NULL"
+		debug "set EBIOS_BUSTYPE to: %s.\n" ${EBIOS_BUSTYPE}
+	fi
+	if [ "${EBIOS_INTERFACE}" = "" ]
+	then
+		EBIOS_INTERFACE="NULL"
+		debug "set EBIOS_INTERFACE to: %s.\n" ${EBIOS_INTERFACE}
+	fi
+
+	# Warning, hexdump not able to handle long long,
+	# PARTITION_START/PARTITION_LENGTH truncated to 32 bits:
+	#PARTITION_START=$(hexdump -v -n 8 -s $((${LINADR_GUJIN} \
+	#				+1+64+1+1+2+4+8+8+16)) -e '/8 "%u"' /dev/mem)
+	PARTITION_START=$(peekl $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8+16)) /dev/mem)
+	#PARTITION_LENGTH=$(hexdump -v -n 8 -s $((${LINADR_GUJIN} \
+	#				+1+64+1+1+2+4+8+8+16+8)) -e '/8 "%u"' /dev/mem)
+	PARTITION_LENGTH=$(peekl $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8+16+8)) /dev/mem)
+	# PARTITION_TYPE: 1 ISO9660, 2 EXT*FS, 3: VFAT
+	PARTITION_TYPE=$(peekb $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8+16+8+8)) /dev/mem)
+	debug "PARTITION_START=%u, PARTITION_LENGTH=%u, PARTITION_TYPE=%u\n" \
+		${PARTITION_START} ${PARTITION_LENGTH} ${PARTITION_TYPE}
+
+	# Search if we have an (ATA) slave disk:
+	if [  ${EBIOS_INTERFACE} = "ATA" \
+		-o ${EBIOS_INTERFACE} = "SATA" \
+		-o ${EBIOS_INTERFACE} = "ATAPI" ]
+	then
+		# uses EBIOS_DEVICE[0]:
+		IS_SLAVE=$(peekb $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8)) /dev/mem)
+		debug "IS_SLAVE=%u (by EBIOS_DEVICE[0])\n" ${IS_SLAVE}
+	else
+		IS_SLAVE=$(( !!(${IDE_MASK} & 0x10) ))
+		debug "IS_SLAVE=%u (by IDE_MASK)\n" ${IS_SLAVE}
+	fi
+
+	# Search the serial number in /dev/disk/by-id/usb-* :
+	# The same system would work for 1394/FIBRE/I2O disks, but I do
+	# not have the hardware to test...
+	if [ ${EBIOS_INTERFACE} = "USB" ]
+	then
+		DISK_BY_ID=$(get_usb_disk_by_id $((${LINADR_GUJIN} +1+64+1+1+2+4+8+8)))
+		if [ "${DISK_BY_ID}" != "" ]
+		then
+			DISK_BY_ID_LINK=$(readlink ${DISK_BY_ID})
+			DISK_BY_ID_LINK=${DISK_BY_ID_LINK#../../}
+		fi
+		if [ "${DISK_BY_ID_LINK}" != "" ]
+		then
+			debug "DISK_BY_ID=%s points to %s\n" \
+				${DISK_BY_ID} ${DISK_BY_ID_LINK}
+		fi
+	fi
+
+	# Search the disk PCI interface in /dev/disk/by-path/pci*:
+	if [ ${EBIOS_BUSTYPE} != "ISA" ]
+	then
+		DISK_BY_PATH=$(find_disk_by_path $((${LINADR_GUJIN} +1+64+1+1+2+4+8)) \
+					${EBIOS_INTERFACE} ${IS_SLAVE} ${IDE_BASE} )
+		if [ "${DISK_BY_PATH}" != "" ]
+		then
+			DISK_BY_PATH_LINK=$(readlink ${DISK_BY_PATH})
+			DISK_BY_PATH_LINK=${DISK_BY_PATH_LINK#../../}
+		fi
+		if [ "${DISK_BY_PATH_LINK}" != "" ]
+		then
+			debug "DISK_BY_PATH=%s points to %s\n" \
+				${DISK_BY_PATH} ${DISK_BY_PATH_LINK}
+		fi
+	fi
+
+	# Find the device with ${DISK_BY_PATH_LINK} and ${DISK_BY_ID_LINK} hints:
+	THEDEVICE=$(find_device ${PARTITION_START} ${PARTITION_LENGTH} \
+				"${DISK_BY_PATH_LINK}" "${DISK_BY_ID_LINK}")
+	debug "THEDEVICE=%s\n" "${THEDEVICE}"
+	if [ "${THEDEVICE}" != "" ]
+	then
+		THEMOUNTPOINT=$(find_create_mount_point ${THEDEVICE} \
+							${PARTITION_TYPE} ${MOUNT_POINT})
+		debug "MOUNTPOINT=%s\n" "${THEMOUNTPOINT}"
+		if [ -e "${THEMOUNTPOINT}/${INT13FILENAME}" ]
+		then
+			debug "Found %s\n" "${THEMOUNTPOINT}/${INT13FILENAME}"
+			printf "%s\n" "${THEMOUNTPOINT}/${INT13FILENAME}"
+			return 0
+		fi
+	fi
+	return 1
+}
+# End Gujin helper functions.
+
 find_livefs ()
 {
 	timeout="${1}"
@@ -1607,6 +2297,11 @@
 				then
 					return 0
 				fi
+			else
+				if gujin_disk_source_file "/isofrom"
+				then
+					return 0
+				fi
 			fi
 			;;
 	esac





Reply to: