mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-11-04 00:16:26 +00:00 
			
		
		
		
	Begin a stumbling effort to generalise my implementation of the Apple Partition Map.
This commit is contained in:
		@@ -1365,6 +1365,7 @@
 | 
				
			|||||||
		4B4C81C428B3C5CD00F84AE9 /* SCSICard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SCSICard.hpp; sourceTree = "<group>"; };
 | 
							4B4C81C428B3C5CD00F84AE9 /* SCSICard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SCSICard.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4C81C828B56CF800F84AE9 /* MacintoshVolume.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MacintoshVolume.hpp; sourceTree = "<group>"; };
 | 
							4B4C81C828B56CF800F84AE9 /* MacintoshVolume.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MacintoshVolume.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4C81C928B56CF800F84AE9 /* MacintoshVolume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacintoshVolume.cpp; sourceTree = "<group>"; };
 | 
							4B4C81C928B56CF800F84AE9 /* MacintoshVolume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacintoshVolume.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							4B4C81CC28B56DD400F84AE9 /* ApplePartitionMap.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ApplePartitionMap.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vic20.cpp; sourceTree = "<group>"; };
 | 
							4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vic20.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vic20.hpp; sourceTree = "<group>"; };
 | 
							4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vic20.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
 | 
							4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
@@ -2925,6 +2926,7 @@
 | 
				
			|||||||
			children = (
 | 
								children = (
 | 
				
			||||||
				4B4C81C828B56CF800F84AE9 /* MacintoshVolume.hpp */,
 | 
									4B4C81C828B56CF800F84AE9 /* MacintoshVolume.hpp */,
 | 
				
			||||||
				4B4C81C928B56CF800F84AE9 /* MacintoshVolume.cpp */,
 | 
									4B4C81C928B56CF800F84AE9 /* MacintoshVolume.cpp */,
 | 
				
			||||||
 | 
									4B4C81CC28B56DD400F84AE9 /* ApplePartitionMap.hpp */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			path = Encodings;
 | 
								path = Encodings;
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										241
									
								
								Storage/MassStorage/Encodings/ApplePartitionMap.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								Storage/MassStorage/Encodings/ApplePartitionMap.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					//  ApplePartitionMap.hpp
 | 
				
			||||||
 | 
					//  Clock Signal
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Thomas Harte on 23/08/2022.
 | 
				
			||||||
 | 
					//  Copyright © 2022 Thomas Harte. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ApplePartitionMap_hpp
 | 
				
			||||||
 | 
					#define ApplePartitionMap_hpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Storage {
 | 
				
			||||||
 | 
					namespace MassStorage {
 | 
				
			||||||
 | 
					namespace Encodings {
 | 
				
			||||||
 | 
					namespace Apple {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
						Implements a device to volume mapping with an Apple Partition Map.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						The @c VolumeProvider provides both the volume to be embedded into a device,
 | 
				
			||||||
 | 
						and device driver information if applicable.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					template <typename VolumeProvider> class PartitionMap {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							/*!
 | 
				
			||||||
 | 
								Sets the drive type to map to and the number of blocks in the underlying partition.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							void set_drive_type(DriveType, size_t number_of_blocks) {
 | 
				
			||||||
 | 
								drive_type_ = drive_type;
 | 
				
			||||||
 | 
								number_of_blocks_ = number_of_blocks;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*!
 | 
				
			||||||
 | 
								@returns The total number of blocks on the entire volume.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							size_t get_number_of_blocks() const {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
									number_of_blocks_ +				// Size of the volume.
 | 
				
			||||||
 | 
									non_volume_blocks();			// Size of everything else.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*!
 | 
				
			||||||
 | 
								Maps from a mass-storage device address to an address
 | 
				
			||||||
 | 
								in the underlying volume.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							ssize_t to_source_address(size_t address) const {
 | 
				
			||||||
 | 
								// The embedded volume is always the last thing on the device.
 | 
				
			||||||
 | 
								return ssize_t(address) - non_volume_blocks();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*!
 | 
				
			||||||
 | 
								Converts from a source data block to one properly encoded for the drive type.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Expected usage:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const size_t source_address = mapper.to_source_address(unit_address);
 | 
				
			||||||
 | 
									if(is_in_range_for_partition(source_address)) {
 | 
				
			||||||
 | 
										return mapper.convert_source_block(source_address, get_block_contents(source_address));
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										return mapper.convert_source_block(source_address);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							std::vector<uint8_t> convert_source_block(ssize_t source_address, std::vector<uint8_t> source_data = {}) {
 | 
				
			||||||
 | 
								// Addresses greater than or equal to zero map to the actual disk image.
 | 
				
			||||||
 | 
								if(source_address >= 0) return source_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Switch to mapping relative to 0, for personal sanity.
 | 
				
			||||||
 | 
								source_address += non_volume_blocks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Block 0 is the device descriptor, which lists the total number of blocks,
 | 
				
			||||||
 | 
								// and provides an offset to the driver, if any.
 | 
				
			||||||
 | 
								if(!source_address) {
 | 
				
			||||||
 | 
									const uint32_t total_device_blocks = uint32_t(get_number_of_blocks());
 | 
				
			||||||
 | 
									const auto driver_size = uint16_t(driver_block_size());
 | 
				
			||||||
 | 
									const auto driver_offset = uint16_t(predriver_blocks());
 | 
				
			||||||
 | 
									const uint8_t driver_count = driver_size > 0 ? 1 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* The driver descriptor. */
 | 
				
			||||||
 | 
									std::vector<uint8_t> driver_description = {
 | 
				
			||||||
 | 
										0x45, 0x52,		/* device signature */
 | 
				
			||||||
 | 
										0x02, 0x00,		/* block size, in bytes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										uint8_t(total_device_blocks >> 24),
 | 
				
			||||||
 | 
										uint8_t(total_device_blocks >> 16),
 | 
				
			||||||
 | 
										uint8_t(total_device_blocks >> 8),
 | 
				
			||||||
 | 
										uint8_t(total_device_blocks),
 | 
				
			||||||
 | 
														/* number of blocks on device */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										0x00, 0x01,		/* reserved (formerly: device type) */
 | 
				
			||||||
 | 
										0x00, 0x01,		/* reserved (formerly: device ID) */
 | 
				
			||||||
 | 
										0x00, 0x00,
 | 
				
			||||||
 | 
										0x00, 0x00,		/* reserved ('sbData', no further explanation given) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										0x00, driver_count,		/* number of device descriptor entries */
 | 
				
			||||||
 | 
										0x00, 0x00,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* first device descriptor's starting block */
 | 
				
			||||||
 | 
										uint8_t(driver_offset >> 8), uint8_t(driver_offset),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* size of device driver */
 | 
				
			||||||
 | 
										uint8_t(driver_size >> 8), uint8_t(driver_size),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										0x00, 0x01,		/*
 | 
				
			||||||
 | 
															More modern documentation: operating system (MacOS = 1)
 | 
				
			||||||
 | 
															Inside Macintosh IV: system type (Mac Plus = 1)
 | 
				
			||||||
 | 
														*/
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									driver_description.resize(512);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return driver_description;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const bool has_driver = volume_provider_.driver_size() > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Blocks 1 and 2 contain entries of the partition map; there's also possibly an entry
 | 
				
			||||||
 | 
								// for the driver.
 | 
				
			||||||
 | 
								if(source_address < 3 + has_driver()) {
 | 
				
			||||||
 | 
									struct Partition {
 | 
				
			||||||
 | 
										const char *name, *type;
 | 
				
			||||||
 | 
										uint32_t start_block, size;
 | 
				
			||||||
 | 
										uint8_t status;
 | 
				
			||||||
 | 
									} partitions[3] = {
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											"MacOS",
 | 
				
			||||||
 | 
											volume_provide_.type(),
 | 
				
			||||||
 | 
											uint32_t(non_volume_blocks()),
 | 
				
			||||||
 | 
											uint32_t(number_of_blocks_),
 | 
				
			||||||
 | 
											0xb7
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											"Apple",
 | 
				
			||||||
 | 
											"Apple_partition_map",
 | 
				
			||||||
 | 
											0x01,
 | 
				
			||||||
 | 
											uint32_t(predriver_blocks()) - 1,
 | 
				
			||||||
 | 
											0x37
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											"Macintosh",
 | 
				
			||||||
 | 
											"Apple_Driver",
 | 
				
			||||||
 | 
											uint32_t(predriver_blocks()),
 | 
				
			||||||
 | 
											driver_block_size(),
 | 
				
			||||||
 | 
											0x7f
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									std::vector<uint8_t> partition(512);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Fill in the fixed fields.
 | 
				
			||||||
 | 
									partition[0] = 'P';	partition[1] = 'M';	/* Signature. */
 | 
				
			||||||
 | 
									partition[7] = 3;						/* Number of partitions. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const Partition &details = partitions[source_address-1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									partition[8] = uint8_t(details.start_block >> 24);
 | 
				
			||||||
 | 
									partition[9] = uint8_t(details.start_block >> 16);
 | 
				
			||||||
 | 
									partition[10] = uint8_t(details.start_block >> 8);
 | 
				
			||||||
 | 
									partition[11] = uint8_t(details.start_block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									partition[84] = partition[12] = uint8_t(details.size >> 24);
 | 
				
			||||||
 | 
									partition[85] = partition[13] = uint8_t(details.size >> 16);
 | 
				
			||||||
 | 
									partition[86] = partition[14] = uint8_t(details.size >> 8);
 | 
				
			||||||
 | 
									partition[87] = partition[15] = uint8_t(details.size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// 32 bytes are allocated for each of the following strings.
 | 
				
			||||||
 | 
									memcpy(&partition[16], details.name, strlen(details.name));
 | 
				
			||||||
 | 
									memcpy(&partition[48], details.type, strlen(details.type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									partition[91] = details.status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// The third entry in this constructed partition map is the driver;
 | 
				
			||||||
 | 
									// add some additional details.
 | 
				
			||||||
 | 
									if(source_address == 3) {
 | 
				
			||||||
 | 
										const auto driver_size = uint16_t(volume_provider_.driver_size());
 | 
				
			||||||
 | 
										const auto driver_checksum = uint16_t(volume_provider_.driver_checksum());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* Driver size in bytes. */
 | 
				
			||||||
 | 
										partition[98] = uint8_t(driver_size >> 8);
 | 
				
			||||||
 | 
										partition[99] = uint8_t(driver_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* Driver checksum. */
 | 
				
			||||||
 | 
										partition[118] = uint8_t(driver_checksum >> 8);
 | 
				
			||||||
 | 
										partition[119] = uint8_t(driver_checksum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* Driver target processor. */
 | 
				
			||||||
 | 
										const char *driver_target = volume_provider_.driver_target();
 | 
				
			||||||
 | 
										memcpy(&partition[120], driver_target, strlen(driver_target));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Various non-zero values that Apple HD SC Tool wrote are below; they are
 | 
				
			||||||
 | 
										// documented as reserved officially, so I don't know their meaning.
 | 
				
			||||||
 | 
										partition[137] = 0x01;
 | 
				
			||||||
 | 
										partition[138] = 0x06;
 | 
				
			||||||
 | 
										partition[143] = 0x01;
 | 
				
			||||||
 | 
										partition[147] = 0x02;
 | 
				
			||||||
 | 
										partition[149] = 0x07;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return partition;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// The remainder of the non-volume area is the driver.
 | 
				
			||||||
 | 
								if(source_address >= predriver_blocks() && source_address < non_volume_blocks()) {
 | 
				
			||||||
 | 
									const uint8_t *driver = volume_provider_.driver();
 | 
				
			||||||
 | 
									const auto offset = (source_address - predriver_blocks()) * 512;
 | 
				
			||||||
 | 
									return std::vector<uint8_t>(&driver[offset], &driver[offset + 512]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Default: return an empty block.
 | 
				
			||||||
 | 
								return std::vector<uint8_t>(512);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							DriveType drive_type_;
 | 
				
			||||||
 | 
							size_t number_of_blocks_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VolumeProvider volume_provider_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t predriver_blocks() const {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
									0x40;					// Holding:
 | 
				
			||||||
 | 
															//	(i) the driver descriptor;
 | 
				
			||||||
 | 
															//	(ii) the partition table; and
 | 
				
			||||||
 | 
															//	(iii) the partition entries.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t non_volume_blocks() const {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
									predriver_blocks() +
 | 
				
			||||||
 | 
									driver_block_size();	// Size of device driver (if any).
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t driver_block_size() const {
 | 
				
			||||||
 | 
								return (volume_provider_.driver_size() + 511) >> 9;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ApplePartitionMap_hpp */
 | 
				
			||||||
@@ -53,7 +53,7 @@ class Mapper {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/*!
 | 
							/*!
 | 
				
			||||||
			Maps from a mass-storage device address to an address
 | 
								Maps from a mass-storage device address to an address
 | 
				
			||||||
			in the underlying [H/M]FS partition.
 | 
								in the underlying HFS partition.
 | 
				
			||||||
		*/
 | 
							*/
 | 
				
			||||||
		ssize_t to_source_address(size_t address);
 | 
							ssize_t to_source_address(size_t address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user