Skip to content

Commit

Permalink
Add Macintosh boot block image
Browse files Browse the repository at this point in the history
This adds a 1024-byte blob with a Macintosh boot image for use with
HFS volumes.  The code that applies it during disk formatting is
currently disabled while we figure out how best to apply it.

Information about the boot block has been added to the HFS doc.

(issue #42)
  • Loading branch information
fadden committed Feb 17, 2025
1 parent f4896ce commit c06ed07
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 3 deletions.
55 changes: 55 additions & 0 deletions DiskArc/FS/HFS-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,61 @@ FXInfo / FndrOpaqueInfo (16 bytes)
+$0c / 4: fdPutAway
```

## Boot Blocks ##

The Macintosh looks for a specific structure in block 0 to decide whether a disk can be booted.
A number of system parameters are stored here, as well as executable code. The format is
documented in IM:Files starting on page 2-57.

The block 0/1 layout is:

```
+$00 / 2: bbID - signature bytes, for HFS this must be $4c $4b ('LK')
+$02 / 4: bbEntry - entry point to boot code, expressed as a 68K BRA.S instruction
+$06 / 2: bbVersion - flag byte and boot block version number
+$08 / 2: bbPageFlags - "used internally"
+$0a /16: bbSysName - system filename, usually "System" (stored as string with leading length byte)
+$1a /16: bbShellName - Finder filename, usually "Finder"
+$2a /16: bbDbg1Name - first debugger filename, usually "MacsBug"
+$3a /16: bbDbg2Name - second debugger filename, usually "Disassembler"
+$4a /16: bbScreenName - file containing startup screen, usually "StartUpScreen"
+$5a /16: bbHelloName - name of startup program, usually "Finder"
+$6a /16: bbScrapName - name of system scrap file, usually "Clipboard"
+$7a / 2: bbCntFCBs - number of FCBs to allocate
+$7c / 2: bbCntEvts - number of event queue elements
+$7e / 4: bb128KSHeap - system heap size on 128K Mac
+$82 / 4: bb256KSHeap - "used internally"
+$86 / 4: bbSysHeapSize - system heap size on machines with >= 512K of RAM
+$8a / 2: filler - reserved
+$8c / 4: bbSysHeapExtra - minimum amount of additional System heap space required
+$90 / 4: bbSysHeapFract - fraction of RAM to make available for system heap
+$94 /nn: executable code, if any
```

The last two heap size fields are only present in "new"-style boot blocks. A bit in the version
flags will tell you whether or not they are present. These values override the earlier fields.

The `bbEntry` value is a 68K branch whose offset is relative to the start of the instruction + 2,
so `60 00 00 86` is a branch to 4 + $86 + 2 = $8c, appropriate for an "old"-style boot block.
A "new"-style boot block should be `60 00 00 8e`, branching to $94.

The `bbVersion` field is documented as a 16-bit value, but the first (high) byte holds flags,
while the second (low) byte holds the boot block version number. The flags are:

bit | meaning
--- | -------
0-4 | reserved, must be 0
5 | set if relative system heap sizing is to be used
6 | set if the boot code in the boot blocks is to be executed
7 | set if the new boot block header format is used

If bit 7 is clear (old format), then bits 5 and 6 are ignored, and the boot code is only executed
if the version is 0x0d. If bit 7 is set (new format), then bit 6 determines whether or not the
code is executed. IM:Files notes:

> Generally, however, the boot code stored on disk is ignored in favor of boot code stored in a
> resource in the System file.
## Miscellaneous ##

HFS volumes can checked with the `fsck.hfs` command. The x86-64 version found on Linux
Expand Down
85 changes: 82 additions & 3 deletions DiskArc/FS/HFS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,14 @@ public void Format(string volumeName, int volumeNum, bool makeBootable) {
throw new ArgumentException("Invalid volume name");
}

// Zero out the boot blocks.
ChunkAccess.WriteBlock(0, HFS_FileDesc.sZeroBlock, 0);
ChunkAccess.WriteBlock(1, HFS_FileDesc.sZeroBlock, 0);
// Write a Macintosh boot block, or just zero it out.
if (makeBootable && false) {
ChunkAccess.WriteBlock(0, sBootBlock0, 0);
ChunkAccess.WriteBlock(1, sBootBlock1, 0);
} else {
ChunkAccess.WriteBlock(0, HFS_FileDesc.sZeroBlock, 0);
ChunkAccess.WriteBlock(1, HFS_FileDesc.sZeroBlock, 0);
}

// Compute geometry.
//
Expand Down Expand Up @@ -1146,6 +1151,80 @@ internal uint AllocBlockToLogiBlock(uint allocBlockNum) {
return VolMDB.AllocBlockStart + allocBlockNum * VolMDB.LogicalPerAllocBlock;
}

/// <summary>
/// <para>Standard Macintosh boot block. Obtained from "bootblockdata" file in
/// <see href="https://github.com/apple-opensource/bless/tree/master/files"/>.</para>
/// <para>Copyright Apple Computer, Inc.</para>
/// </summary>
private static readonly byte[] sBootBlock0 = new byte[512] {
0x4c,0x4b,0x60,0x00,0x00,0x86,0x44,0x18,0x00,0x00,0x06,0x53,0x79,0x73,0x74,0x65,
0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x46,0x69,0x6e,0x64,0x65,
0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x4d,0x61,0x63,0x73,0x42,
0x75,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x44,0x69,0x73,0x61,0x73,
0x73,0x65,0x6d,0x62,0x6c,0x65,0x72,0x00,0x00,0x00,0x0d,0x53,0x74,0x61,0x72,0x74,
0x55,0x70,0x53,0x63,0x72,0x65,0x65,0x6e,0x00,0x00,0x06,0x46,0x69,0x6e,0x64,0x65,
0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x43,0x6c,0x69,0x70,0x62,
0x6f,0x61,0x72,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x14,0x00,0x00,
0x43,0x00,0x00,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x4a,0x78,0x02,0x8e,0x6b,0x46,
0x20,0x78,0x02,0xae,0x32,0x28,0x00,0x08,0x7c,0xfe,0x54,0x46,0x30,0x3b,0x60,0x3c,
0x67,0x58,0xb2,0x40,0x66,0xf4,0x0c,0x01,0x00,0x76,0x62,0x10,0x20,0x78,0x02,0xa6,
0xd1,0xfa,0xff,0xd4,0xa0,0x57,0x21,0xf8,0x02,0xa6,0x01,0x18,0x58,0x4f,0x2e,0x0f,
0x61,0x38,0x32,0x3b,0x60,0x22,0x4a,0x40,0x67,0x04,0x32,0x3b,0x60,0x24,0x20,0x78,
0x02,0xae,0x4e,0xf0,0x10,0x00,0x70,0x62,0xa9,0xc9,0x00,0x75,0x02,0x76,0x01,0x78,
0x03,0x7a,0x06,0x7c,0x00,0x00,0x0a,0x44,0x09,0x0e,0x0f,0x1c,0x30,0xe6,0x1d,0x96,
0x0b,0x82,0x0a,0x52,0x11,0xae,0x33,0x6e,0x20,0x3e,0x41,0xfa,0xff,0x0e,0x43,0xf8,
0x0a,0xd8,0x70,0x10,0xa0,0x2e,0x41,0xfa,0xff,0x12,0x43,0xf8,0x02,0xe0,0x70,0x10,
0xa0,0x2e,0x41,0xfa,0xff,0x56,0x43,0xf8,0x09,0x70,0x21,0xc9,0x09,0x6c,0x70,0x10,
0xa0,0x2e,0x30,0x3a,0xff,0x58,0xa0,0x6d,0x30,0x3a,0xff,0x50,0xa0,0x6c,0x20,0x47,
0x31,0x78,0x02,0x10,0x00,0x16,0xa0,0x0f,0x66,0x54,0x42,0xa8,0x00,0x12,0x42,0x68,
0x00,0x1c,0xa2,0x07,0x66,0x40,0x28,0x68,0x00,0x5e,0x21,0x68,0x00,0x5a,0x00,0x30,
0x67,0x10,0x21,0x7c,0x45,0x52,0x49,0x4b,0x00,0x1c,0x70,0x01,0xa2,0x60,0x66,0x26,
0xa0,0x15,0x55,0x4f,0xa9,0x95,0x4a,0x5f,0x6b,0x1a,0x59,0x4f,0x2f,0x3c,0x62,0x6f,
0x6f,0x74,0x3f,0x3c,0x00,0x02,0xa9,0xa0,0x20,0x1f,0x67,0x12,0x58,0x4f,0x26,0x40,
0x20,0x53,0x4e,0xd0,0x70,0x2b,0x3f,0x00,0x20,0x47,0xa0,0x0e,0x30,0x1f,0x4e,0x75,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda
};
private static readonly byte[] sBootBlock1 = new byte[512] {
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda
};

#endregion Miscellaneous
}
}

0 comments on commit c06ed07

Please sign in to comment.