Files
fluxengine/lib/data/layout.h
2025-10-31 01:19:06 +01:00

235 lines
6.6 KiB
C++

#ifndef LAYOUT_H
#define LAYOUT_H
#include "lib/data/disk.h"
#include "lib/config/layout.pb.h"
#include "lib/config/config.h"
#include "lib/data/locations.h"
class ConfigProto;
struct LogicalTrackLayout
{
/* Physical cylinder of the first element of the group. */
unsigned physicalCylinder;
/* Physical head of the first element of the group. */
unsigned physicalHead;
/* Size of this group. */
unsigned groupSize;
/* Logical cylinder of this track. */
unsigned logicalCylinder = 0;
/* Logical side of this track. */
unsigned logicalHead = 0;
/* The number of sectors in this track. */
unsigned numSectors = 0;
/* Number of bytes in a sector. */
unsigned sectorSize = 0;
/* Sector IDs in sector ID order. This is the order in which the appear in
* disk images. */
std::vector<unsigned> naturalSectorOrder;
/* Sector IDs in disk order. This is the order they are written to the disk.
*/
std::vector<unsigned> diskSectorOrder;
/* Sector IDs in filesystem order. This is the order in which the filesystem
* uses them. */
std::vector<unsigned> filesystemSectorOrder;
/* Mapping of sector ID to filesystem ordering. */
std::map<unsigned, unsigned> sectorIdToFilesystemOrdering;
/* Mapping of sector ID to natural ordering. */
std::map<unsigned, unsigned> sectorIdToNaturalOrdering;
};
struct PhysicalTrackLayout
{
/* Physical location of this track. */
unsigned physicalCylinder;
/* Physical side of this track. */
unsigned physicalHead;
/* Which member of the group this is. */
unsigned groupOffset;
/* The logical track that this track is part of. */
std::shared_ptr<const LogicalTrackLayout> logicalTrackLayout;
};
class DiskLayout
{
public:
DiskLayout(const ConfigProto& config = globalConfig());
/* Makes a simplified layout for testing. */
DiskLayout(unsigned numCylinders,
unsigned numHeads,
unsigned numSectors,
unsigned sectorSize);
public:
/* Logical size. */
unsigned numLogicalCylinders;
unsigned numLogicalHeads;
/* Physical size and properties. */
unsigned minPhysicalCylinder, maxPhysicalCylinder;
unsigned minPhysicalHead, maxPhysicalHead;
unsigned groupSize; /* Number of physical cylinders per logical cylinder */
unsigned headBias; /* Physical cylinder offset */
unsigned headWidth; /* Width of the physical head */
bool swapSides; /* Whether sides need to be swapped */
unsigned totalBytes; /* Total number of bytes on the disk. */
/* Physical and logical layouts by location. */
std::map<CylinderHead, std::shared_ptr<const PhysicalTrackLayout>>
layoutByPhysicalLocation;
std::map<CylinderHead, std::shared_ptr<const LogicalTrackLayout>>
layoutByLogicalLocation;
/* Ordered lists of physical and logical locations. */
std::vector<CylinderHead> logicalLocations;
std::vector<CylinderHead> logicalLocationsInFilesystemOrder;
std::vector<CylinderHead> physicalLocations;
/* Ordered lists of sector locations, plus the reverse mapping. */
std::vector<LogicalLocation> logicalSectorLocationsInFilesystemOrder;
std::map<LogicalLocation, unsigned> blockIdByLogicalSectorLocation;
std::vector<CylinderHeadSector> physicalSectorLocationsInFilesystemOrder;
/* Mapping from logical location to sector offset and back again. */
std::map<unsigned, LogicalLocation> logicalSectorLocationBySectorOffset;
std::map<LogicalLocation, unsigned> sectorOffsetByLogicalSectorLocation;
public:
unsigned remapCylinderPhysicalToLogical(unsigned physicalCylinder) const
{
return (physicalCylinder - headBias) / groupSize;
}
unsigned remapCylinderLogicalToPhysical(unsigned logicalCylinder) const
{
return headBias + logicalCylinder * groupSize;
}
unsigned remapHeadPhysicalToLogical(unsigned physicalHead) const
{
return physicalHead ^ swapSides;
}
unsigned remapHeadLogicalToPhysical(unsigned logicalHead) const
{
return logicalHead ^ swapSides;
}
/* Given a list of CylinderHead locations, determines the minimum and
* maximum track and side settings. */
struct LayoutBounds
{
std::strong_ordering operator<=>(
const LayoutBounds& other) const = default;
int minCylinder, maxCylinder, minHead, maxHead;
};
static LayoutBounds getBounds(std::ranges::view auto keys)
{
LayoutBounds r{.minCylinder = INT_MAX,
.maxCylinder = INT_MIN,
.minHead = INT_MAX,
.maxHead = INT_MIN};
for (const auto& ch : keys)
{
r.minCylinder = std::min<int>(r.minCylinder, ch.cylinder);
r.maxCylinder = std::max<int>(r.maxCylinder, ch.cylinder);
r.minHead = std::min<int>(r.minHead, ch.head);
r.maxHead = std::max<int>(r.maxHead, ch.head);
}
return r;
}
LayoutBounds getPhysicalBounds() const;
LayoutBounds getLogicalBounds() const;
};
static std::shared_ptr<DiskLayout> createDiskLayout(
const ConfigProto& config = globalConfig())
{
return std::make_shared<DiskLayout>(config);
}
class TrackInfo
{
public:
TrackInfo() {}
private:
/* Can't copy. */
TrackInfo(const TrackInfo&);
TrackInfo& operator=(const TrackInfo&);
public:
unsigned numCylinders = 0;
unsigned numHeads = 0;
/* The number of sectors in this track. */
unsigned numSectors = 0;
/* Physical location of this track. */
unsigned physicalCylinder = 0;
/* Physical side of this track. */
unsigned physicalHead = 0;
/* Logical location of this track. */
unsigned logicalCylinder = 0;
/* Logical side of this track. */
unsigned logicalHead = 0;
/* The number of physical tracks which need to be written for one logical
* track. */
unsigned groupSize = 0;
/* Number of bytes in a sector. */
unsigned sectorSize = 0;
/* Sector IDs in sector ID order. This is the order in which the appear in
* disk images. */
std::vector<unsigned> naturalSectorOrder;
/* Sector IDs in disk order. This is the order they are written to the disk.
*/
std::vector<unsigned> diskSectorOrder;
/* Sector IDs in filesystem order. This is the order in which the filesystem
* uses them. */
std::vector<unsigned> filesystemSectorOrder;
/* Mapping of filesystem order to natural order. */
std::map<unsigned, unsigned> filesystemToNaturalSectorMap;
/* Mapping of natural order to filesystem order. */
std::map<unsigned, unsigned> naturalToFilesystemSectorMap;
};
#endif