Skip to content

Boot Floppy Builder

Levente Santha edited this page May 15, 2026 · 1 revision

Boot Floppy Builder

Ant task that creates GRUB-bootable FAT disk images by wrapping the boot image in a FAT filesystem with GRUB stage1/stage2 bootloaders.

Overview

BootFloppyBuilder (org.jnode.build.BootFloppyBuilder) is an Ant task that creates bootable disk images. Despite its name, it does not create actual floppy disks — it creates file-backed block devices formatted as FAT filesystems with GRUB embedded in the boot sector. The actual build uses its subclass BootDiskBuilder, which extends BootFloppyBuilder to create partitioned hard disk images with an MBR.

The boot disk builder sits in the build pipeline after Build---BootImageBuilder-Internals (which creates the raw boot image binary) and before the optional Boot-CD-ROM-Builder (which wraps the disk image in an ISO-9660 CD-ROM).

The pipeline is:

BootImageBuilder → bootimage.bin
  → gzip → jnode.kernel.gz
    → BootDiskBuilder → FAT disk image with GRUB (jnode.disk)
      → create-cdrom → ISO-9660 CD-ROM image (jnode.iso)

Key Components

Class / File Role
builder/src/builder/org/jnode/build/BootFloppyBuilder.java Base Ant task: creates 1.44 MB FAT floppy image with GRUB
builder/src/builder/org/jnode/build/BootDiskBuilder.java Subclass: creates partitioned hard disk image with MBR, IBM partition table, and .pln VMware descriptor
fs/src/fs/org/jnode/fs/fat/GrubFatFormatter.java Formats device as FAT, embeds GRUB stage1 (boot sector) and stage2
fs/src/fs/org/jnode/fs/fat/GrubBootSector.java GRUB boot sector structure and patching
fs/src/fs/org/jnode/fs/fat/FatType.java FAT type enumeration (FAT12, FAT16, FAT32)
fs/src/fs/org/jnode/fs/fat/FatFileSystem.java FAT filesystem implementation used to copy files onto the image
all/build-x86.xml Ant build file defining the boot-disk target that invokes BootDiskBuilder

How It Works

BootFloppyBuilder (Base Class)

BootFloppyBuilder extends org.apache.tools.ant.Task and creates a 1.44 MB floppy image (1440 × 1024 bytes):

public class BootFloppyBuilder extends Task {
    private File destFile;
    private String stage1ResourceName;
    private String stage2ResourceName;
    private ArrayList<FileSet> fileSets;

    public void execute() throws BuildException {
        if (isExecuteNeeded()) {
            createImage();
        }
    }

    protected void createImage() throws IOException, DriverException, FileSystemException {
        // Create file-backed block device
        final FileDevice newFd = new FileDevice(destFile, "rw");
        newFd.setLength(getDeviceLength());  // 1.44 MB

        // Format as GRUB-bootable FAT
        formatDevice(newFd);

        // Copy files onto the FAT filesystem
        final Device sysDev = getSystemDevice(newFd);
        final BlockDeviceAPI sysDevApi = sysDev.getAPI(BlockDeviceAPI.class);
        copySystemFiles(sysDev);
        sysDevApi.flush();
    }

    protected long getDeviceLength() {
        return 1440 * 1024;  // 1.44 MB floppy
    }

    protected GrubFatFormatter createFormatter() {
        return new GrubFatFormatter(0, stage1ResourceName, stage2ResourceName);
    }
}

Key behaviors:

  1. Incremental build check: isExecuteNeeded() compares the destination file's last-modified timestamp against the source files. If the output is newer, the task is skipped.
  2. GRUB embedding: GrubFatFormatter formats the device as FAT, then writes GRUB stage1 into the boot sector and stage2 starting at sector 1.
  3. File copying: Copies file sets (kernel, GRUB menu, initjars) onto the FAT filesystem using FatFileSystem.

BootDiskBuilder (Subclass)

BootDiskBuilder extends BootFloppyBuilder and creates a partitioned hard disk image:

Aspect BootFloppyBuilder BootDiskBuilder
Device size Fixed 1.44 MB Configurable via geometry (cylinders/heads/sectors)
Partition table None (whole-disk FAT) MBR with IBM partition table (FAT16 <32M)
FAT type FAT12 (floppy) FAT16 <32M
System device Root device itself Partition 0 (via MappedFSBlockDeviceSupport)
Formatter GrubFatFormatter(0, stage1, stage2) GrubFatFormatter(bps, spc, geom, FatType.FAT16, 1, stage1, stage2)
Extra output None .pln file (VMware disk descriptor for VirtualBox/VMware)
Geometry Implicit (1.44MB floppy) Explicit Geometry(cylinders, heads, sectors)

BootDiskBuilder's formatDevice() creates an MBR with an IBM partition table, formats partition 0, and fixes up the stage2 sector reference in the MBR. It also writes a .pln file with cylinder/head/sector geometry for VMware/VirtualBox.

GRUB Integration

GrubFatFormatter handles GRUB embedding:

public class GrubFatFormatter {
    // Two constructors:
    // 1. Floppy variant: uses FatFormatter.fat144FloppyFormatter
    // 2. Hard-disk variant: uses FatFormatter.HDFormatter with custom geometry

    public void format(BlockDeviceAPI device) throws IOException {
        // 1. Format device as FAT via FatFormatter
        // 2. Write GRUB stage2 to sector 1+
        // 3. Patch stage2 with:
        //    - Boot sector offset
        //    - Install partition number
        //    - Optional config file path
    }

    private void createBootSector() {
        // Load GRUB stage1 (512 bytes) from classpath resource
        // Load GRUB stage2 from classpath resource
        // Write stage1 to boot sector
    }
}

GRUB stage1 (512 bytes) is written to the boot sector. Stage2 is written starting at sector 1 and is patched with the boot sector offset and partition number so it can find the kernel.

Build Target Configuration

The boot-disk target in all/build-x86.xml:

<target name="boot-disk" depends="java-image" unless="no.bootdisk">
    <taskdef name="bootdisk" classname="org.jnode.build.BootDiskBuilder"
             classpathref="cp-x86" />
    <property name="bootdisk.dir" value="${my-build.dir}/${jnode.bits}bits/bootdisk" />
    <mkdir dir="${bootdisk.dir}" />
    <mkdir dir="${bootdisk.dir}/boot/grub" />
    <copy file="${jnode.kernel}" todir="${bootdisk.dir}" />
    <copy file="${grub.menu}" todir="${bootdisk.dir}/boot/grub" />
    <copy todir="${bootdisk.dir}">
        <fileset dir="${initjars.dir}">
            <include name="default.jgz"/>
            <include name="full.jgz"/>
        </fileset>
    </copy>
    <bootdisk destfile="${jnode.disk}"
              stage1ResourceName="${grub.stage1.name}"
              stage2ResourceName="${grub.stage2.name}"
              plnfile="${jnode.disk.pln}"
              geometry="${jnode.disk.geometry}">
        <fileset dir="${bootdisk.dir}" />
    </bootdisk>
</target>

The target:

  1. Depends on java-image (which runs BootImageBuilder to create the boot image)
  2. Can be skipped by setting the no.bootdisk property
  3. Copies the kernel (jnode.kernel), GRUB menu, and initjars (default.jgz, full.jgz) into a staging directory
  4. Invokes the <bootdisk> task with the staging directory as a fileset

Relationship to BootImageBuilder

BootFloppyBuilder and BootImageBuilder serve different purposes:

Aspect BootFloppyBuilder BootImageBuilder
Inheritance extends Task (Ant task) extends AbstractBootImageBuilder
Purpose Creates a FAT filesystem image with GRUB Compiles Java + native code into a bootable binary
Output FAT-formatted disk image Raw boot image binary (kernel + Java heap)
GRUB Embeds GRUB stage1/stage2 into FAT boot sector No GRUB; uses Multiboot header
FAT filesystem Yes — creates FAT, copies files No — emits raw native stream
JIT compilation None Pre-compiles Java classes using L1/L2 JIT
Relationship Post-processing: wraps boot image in FAT Creates the boot image that gets placed into FAT

Relationship to Boot CD-ROM Builder

The Boot-CD-ROM-Builder creates ISO-9660 CD-ROM images. The boot disk image created by BootDiskBuilder can be wrapped into an ISO using the create-cdrom macro:

BootDiskBuilder → jnode.disk (FAT disk image)
  → create-cdrom → jnode.iso (ISO-9660 CD-ROM)

The cd-x86-lite and cd-x86_64-lite Ant targets orchestrate this pipeline.

Gotchas & Non-Obvious Behavior

  • Naming mismatch: The class is called "BootFloppyBuilder" but its own Javadoc says "in fact, it's not a floppy but a cdrom image in the iso format". In practice, BootFloppyBuilder creates a 1.44MB FAT floppy image, while BootDiskBuilder creates a partitioned hard disk image. Neither creates an ISO directly — that's done by the create-cdrom macro.
  • BootDiskBuilder is what's actually used: The Ant build system uses BootDiskBuilder (the subclass), not BootFloppyBuilder directly. The <bootdisk> taskdef points to org.jnode.build.BootDiskBuilder.
  • no.bootdisk property: The boot-disk target can be skipped by setting this property, which is available as an install script option in all/conf-source/script.xml.
  • GRUB stage1/stage2 are classpath resources: The GRUB bootloader binaries are loaded from the classpath (default names: "stage1", "stage2"). They must be available on the build classpath.
  • Incremental build: BootFloppyBuilder checks timestamps before executing. If the destination file is newer than all source files, the task is skipped.
  • VMware .pln file: BootDiskBuilder writes a .pln file with cylinder/head/sector geometry. This is used by VMware/VirtualBox to create the correct virtual disk geometry.
  • FAT16 vs FAT12: BootFloppyBuilder uses FAT12 (floppy format), while BootDiskBuilder uses FAT16 <32M (hard disk format). The formatter is selected based on the constructor parameters.
  • Partition 0 is the system partition: BootDiskBuilder's getSystemDevice() returns partition 0 (via MappedFSBlockDeviceSupport), not the root device. This is where the FAT filesystem and GRUB are placed.

Related Pages

Clone this wiki locally