mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Begin a stumbling effort to generalise my implementation of the Apple Partition Map.
This commit is contained in:
parent
64c5b84b8b
commit
1555b51d99
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user