summaryrefslogtreecommitdiff
path: root/tools/atari-hd-image.sh
diff options
context:
space:
mode:
authorEero Tamminen <eerot@users.berlios.de>2011-08-29 20:33:10 (GMT)
committerEero Tamminen <eerot@users.berlios.de>2011-08-29 20:33:10 (GMT)
commit0a43c8e65a9aaeb9abaf7cd5b92826a7098f11c9 (patch)
tree4f7875e5cbd536b75b5f7df3a97da19212aa7c4d /tools/atari-hd-image.sh
parent99c6e44721306390c790261f9d31a310199151f7 (diff)
downloadhatari-0a43c8e65a9aaeb9abaf7cd5b92826a7098f11c9.zip
hatari-0a43c8e65a9aaeb9abaf7cd5b92826a7098f11c9.tar.gz
Latest sfdisk is broken. Write suitable MBR with inlined Python code
Diffstat (limited to 'tools/atari-hd-image.sh')
-rwxr-xr-xtools/atari-hd-image.sh170
1 files changed, 106 insertions, 64 deletions
diff --git a/tools/atari-hd-image.sh b/tools/atari-hd-image.sh
index 609c66b..029145e 100755
--- a/tools/atari-hd-image.sh
+++ b/tools/atari-hd-image.sh
@@ -1,16 +1,12 @@
-#!/bin/bash
-# script for creating a compatible DOS HD image for Hatari
-# with a single FAT16 partition of given size
-#
-# requires bash as other shells (like dash) don't always interpret
-# the DOS Master Boot Record checksum octal values given to
-# "echo" correctly (can be checked with "od -t o1 $diskfile").
+#!/bin/sh
+# script for creating a compatible DOS HD image for Hatari with
+# a single FAT16 partition of given size, with given contents
# defaults for disk attributes
diskfile=hd.img # HD image filename
partname=DOS # partition name
-# no args or first arg has non-digit characters
+# no args or first arg has non-digit characters?
if [ $# -lt 1 ] || [ \! -z "$(echo $1|tr -d 0-9)" ]; then
name=${0##*/}
echo
@@ -37,8 +33,8 @@ PATH=/sbin:$PATH
export PATH
# check tools
-if [ -z $(which sfdisk) ] || [ -z $(which mkdosfs) ]; then
- echo "ERROR: either sfdisk or mkdosfs missing!"
+if [ -z $(which mkdosfs) ] || [ -z $(which python) ]; then
+ echo "ERROR: either mkdosfs or python tool missing!"
exit 1
fi
@@ -51,15 +47,16 @@ if [ $1 -gt 256 ]; then
echo "ERROR: EmuTOS supports only partitions up to 256 (MB)."
exit 1
fi
+
# disk geometry
-cylinders=$((4*$1)) # 16*32*512 is 1/4MB
+skip=0 # alignment / "padding" sectors between MBR before partition
diskheads=16
-tracksectors=32 # same as used by mkdosfs
+tracksectors=32 # same as used by mkdosfs
sectorsize=512
-partsize=$(($cylinders*$diskheads*$tracksectors*$sectorsize))
-# counts in sectors with correct disk geometry
-sfdisk="sfdisk -uS -C $cylinders -H $diskheads -S $tracksectors"
+# partition size in sectors:
+# 16*32*512 is 1/4MB -> multiply by 4 to get number of required sectors
+partsectors=$((4*$1*$diskheads*$tracksectors))
# check optional arguments
if [ \! -z $2 ]; then
@@ -108,44 +105,95 @@ trap exit_cleanup EXIT
echo
step=1
-echo "$step) Creating $1MB sparse disk image..."
-echo "dd if=/dev/zero of=$diskfile bs=1 count=0 seek=$((512+partsize))"
-dd if=/dev/zero of=$diskfile bs=$((512+partsize)) count=1
-
-echo
-step=$(($step+1))
-echo "$step) Creating DOS Master Boot Record partition table..."
-
-echo "Add DOS MBR signature needed by sfdisk:"
-echo -e "\0125\0252" | dd of=$diskfile bs=1 seek=510 count=2
-
-echo "Add partition table to MBR with single FAT16 partition:"
-clusters=$(($partsize/1024))
-if [ $clusters -le 32765 ]; then
- fatbits=16
- parttype="0x4"
-else
- fatbits=16
- parttype="0x6"
-fi
-echo "Using FAT$fatbits partition type $parttype"
-echo "$sfdisk --no-reread $diskfile: ,,$parttype,*"
-$sfdisk --no-reread $diskfile << EOF
-,,$parttype,*
+echo "$step) Creating DOS Master Boot Record / partition table..."
+# See:
+# - http://en.wikipedia.org/wiki/Master_boot_record
+# - http://en.wikipedia.org/wiki/Cylinder-head-sector
+# - http://en.wikipedia.org/wiki/File_Allocation_Table#Boot_Sector
+# For DOS MBR, the values are little endian.
+# -----------
+python << EOF
+#!/usr/bin/env python
+mbr = bytearray(512)
+
+def set_long(idx, value):
+ mbr[idx+0] = value & 0xff
+ mbr[idx+1] = value >> 8 & 0xff
+ mbr[idx+2] = value >> 16 & 0xff
+ mbr[idx+3] = value >> 24
+
+def set_word(idx, value):
+ mbr[idx] = value & 0xff
+ mbr[idx+1] = value >> 8 & 0xff
+
+def set_CHS(idx, values):
+ c, h, s = values
+ print "CHS: %3d,%3d,%3d @ $%x" % (c,h,s,idx)
+ mbr[idx] = h
+ mbr[idx+1] = (s & 0x3F) | ((c >> 2) & 0xC0)
+ mbr[idx+2] = c & 0xFF
+
+def LBA2CHS(lba):
+ c = lba / ($tracksectors * $diskheads)
+ h = (lba / $tracksectors) % $diskheads
+ s = (lba % $tracksectors) + 1
+ return (c,h,s)
+
+# disk size
+sectors = 1 + $skip + $partsectors
+if sectors < 65536:
+ set_word(0x13, sectors)
+ set_long(0x20, sectors)
+ parttype=0x4
+else:
+ set_long(0x20, sectors)
+ parttype=0x6
+
+# reserved sectors = MBR
+mbr[0x0E] = 1
+
+# CHS information
+set_word(0x0B, $sectorsize)
+mbr[0x0D] = 2 # sectors / cluster
+set_word(0x18, $tracksectors)
+set_word(0x1A, $diskheads)
+
+# non-removable disk
+mbr[0x15] = 0xF8
+mbr[0x24] = 0x80
+
+# partition size in sectors
+partsectors = $partsectors - 1
+# first partition takes all
+offset = 0x1BE
+mbr[offset] = 0x80 # bootable
+mbr[offset+4] = parttype
+# partition start & sector count in LBA
+set_long(offset + 0x08, 1)
+set_long(offset + 0x0C, partsectors)
+# partition start & end in CHS
+set_CHS(offset + 1, LBA2CHS(1))
+set_CHS(offset + 5, LBA2CHS(partsectors))
+# 3 last partitions are empty
+for i in (1,2,3):
+ offset += 0x10
+ set_long(offset + 0x08, partsectors+1)
+ set_long(offset + 0x0C, 0)
+ set_CHS(offset + 1, LBA2CHS(partsectors+1))
+ set_CHS(offset + 5, LBA2CHS(partsectors))
+
+# MBR signature
+mbr[0x1FE] = 0x55
+mbr[0x1FF] = 0xAA
+
+open("$diskfile", "wb").write(bytes(mbr))
EOF
-if [ $? -ne 0 ]; then
- error="'sfdisk' failed."
- exit 2
-fi
+# -----------
+od -t x1 $diskfile
echo
step=$(($step+1))
-echo "$step) Creating Atari TOS compatible DOS partition..."
-sectors=$($sfdisk -l $diskfile|awk '/\*/{print $5}')
-if [ -z "$sectors" ] || [ $sectors -eq 0 ]; then
- error="couldn't get partition size information."
- exit 2
-fi
+echo "$step) Creating an Atari TOS compatible DOS partition..."
# mkdosfs keeps the sector count below 32765 when -A is used by increasing
# the logical sector size (this is for TOS compatibility, -A guarantees
# also 2 sectors / cluster and Atari serial number etc). Mtools barfs
@@ -153,22 +201,21 @@ fi
# suitable cluster count & corresponding track size and align (decrease)
# the file system sector count accordingly.
tracksize=32
-clustertmp=$((sectors/2))
-echo "Sectors: $sectors, sectors/track: $tracksize, clusters: $clustertmp"
+clustertmp=$((partsectors/2))
+echo "Sectors: $partsectors, sectors/track: $tracksize, clusters: $clustertmp"
while [ $clustertmp -gt 32765 ]; do
clustertmp=$((clustertmp/2))
tracksize=$(($tracksize*2))
echo "Doubling sector size as >32765 clusters -> $clustertmp clusters"
done
-origsectors=$sectors
-sectors=$(($sectors/$tracksize))
+sectors=$(($partsectors/$tracksize))
sectors=$(($sectors*$tracksize))
kilobytes=$(($sectors/2))
-if [ $sectors -ne $origsectors ]; then
- echo "Align sector count with clusters/sectors/track: $origsectors -> $sectors ($kilobytes kB)"
+if [ $sectors -ne $partsectors ]; then
+ echo "Align sector count with clusters/sectors/track: $partsectors -> $sectors ($kilobytes kB)"
fi
-echo "mkdosfs -A -F $fatbits -n $partname -C $tmppart $kilobytes"
-mkdosfs -A -n $partname -C $tmppart $kilobytes
+echo "mkdosfs -A -F 16 -n $partname -C $tmppart $kilobytes"
+mkdosfs -A -F 16 -n $partname -C $tmppart $kilobytes
if [ \! -z $contentdir ]; then
echo
@@ -187,13 +234,8 @@ echo
step=$(($step+1))
# copy the partition into disk
echo "$step) Copying the partition to disk image..."
-start=$($sfdisk -l $diskfile|awk '/\*/{print $3}')
-if [ -z "$sectors" ] || [ $sectors -eq 0 ]; then
- error="couldn't get partition start information."
- exit 2
-fi
-echo "dd if=$tmppart of=$diskfile bs=512 seek=$start count=$sectors"
-dd if=$tmppart of=$diskfile bs=512 seek=$start count=$sectors
+echo "dd if=$tmppart of=$diskfile bs=512 seek=$((1+$skip)) count=$sectors"
+dd if=$tmppart of=$diskfile bs=512 seek=$((1+$skip)) count=$sectors
step=$(($step+1))
# cleanup is done by exit_cleanup() trap