|
|
@@ -43,9 +43,148 @@ extern "C" {
|
|
|
#define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 512
|
|
|
#endif
|
|
|
|
|
|
+#ifndef PLATFORM_HAS_ROM_DRIVE
|
|
|
+// Dummy defines for platforms without ROM drive support
|
|
|
+#define AZPLATFORM_ROMDRIVE_PAGE_SIZE 1024
|
|
|
+uint32_t azplatform_get_romdrive_maxsize() { return 0; }
|
|
|
+bool azplatform_read_romdrive(uint8_t *dest, uint32_t start, uint32_t count) { return false; }
|
|
|
+bool azplatform_write_romdrive(const uint8_t *data, uint32_t start, uint32_t count) { return false; }
|
|
|
+#endif
|
|
|
+
|
|
|
// SD card sector size is always 512 bytes
|
|
|
#define SD_SECTOR_SIZE 512
|
|
|
|
|
|
+/************************************************/
|
|
|
+/* ROM drive support (in microcontroller flash) */
|
|
|
+/************************************************/
|
|
|
+
|
|
|
+struct romdrive_hdr_t {
|
|
|
+ char magic[8]; // "ROMDRIVE"
|
|
|
+ int scsi_id;
|
|
|
+ uint32_t imagesize;
|
|
|
+ uint32_t blocksize;
|
|
|
+ S2S_CFG_TYPE drivetype;
|
|
|
+ uint32_t reserved[32];
|
|
|
+};
|
|
|
+
|
|
|
+// Check if the romdrive is present
|
|
|
+static bool check_romdrive(romdrive_hdr_t *hdr)
|
|
|
+{
|
|
|
+ if (!azplatform_read_romdrive((uint8_t*)hdr, 0, sizeof(romdrive_hdr_t)))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (memcmp(hdr->magic, "ROMDRIVE", 8) != 0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hdr->imagesize <= 0 || hdr->scsi_id < 0 || hdr->scsi_id > 8)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// Load an image file to romdrive
|
|
|
+bool scsiDiskProgramRomDrive(const char *filename, int scsi_id, int blocksize, S2S_CFG_TYPE type)
|
|
|
+{
|
|
|
+ FsFile file = SD.open(filename, O_RDONLY);
|
|
|
+ if (!file.isOpen())
|
|
|
+ {
|
|
|
+ azlog("---- Failed to open: ", filename);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ uint64_t filesize = file.size();
|
|
|
+ uint32_t maxsize = azplatform_get_romdrive_maxsize() - AZPLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
+
|
|
|
+ azlog("---- SCSI ID: ", scsi_id, " blocksize ", blocksize, " type ", (int)type);
|
|
|
+ azlog("---- ROM drive maximum size is ", (int)azplatform_get_romdrive_maxsize(),
|
|
|
+ " bytes, image file is ", (int)file.size(), " bytes");
|
|
|
+
|
|
|
+ if (filesize > maxsize)
|
|
|
+ {
|
|
|
+ azlog("---- Image size exceeds ROM space, not loading");
|
|
|
+ file.close();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ romdrive_hdr_t hdr = {};
|
|
|
+ memcpy(hdr.magic, "ROMDRIVE", 8);
|
|
|
+ hdr.scsi_id = scsi_id;
|
|
|
+ hdr.imagesize = filesize;
|
|
|
+ hdr.blocksize = blocksize;
|
|
|
+ hdr.drivetype = type;
|
|
|
+
|
|
|
+ // Program the drive metadata header
|
|
|
+ if (!azplatform_write_romdrive((const uint8_t*)&hdr, 0, AZPLATFORM_ROMDRIVE_PAGE_SIZE))
|
|
|
+ {
|
|
|
+ azlog("---- Failed to program ROM drive header");
|
|
|
+ file.close();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Program the drive contents
|
|
|
+ uint32_t pages = (filesize + AZPLATFORM_ROMDRIVE_PAGE_SIZE - 1) / AZPLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
+ for (uint32_t i = 0; i < pages; i++)
|
|
|
+ {
|
|
|
+ if (!file.read(scsiDev.data, AZPLATFORM_ROMDRIVE_PAGE_SIZE) ||
|
|
|
+ !azplatform_write_romdrive(scsiDev.data, (i + 1) * AZPLATFORM_ROMDRIVE_PAGE_SIZE, AZPLATFORM_ROMDRIVE_PAGE_SIZE))
|
|
|
+ {
|
|
|
+ azlog("---- Failed to program ROM drive page ", (int)i);
|
|
|
+ file.close();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ file.close();
|
|
|
+
|
|
|
+ char newname[MAX_FILE_PATH * 2] = "";
|
|
|
+ strlcat(newname, filename, sizeof(newname));
|
|
|
+ strlcat(newname, "_loaded", sizeof(newname));
|
|
|
+ SD.rename(filename, newname);
|
|
|
+ azlog("---- ROM drive programming successful, image file renamed to ", newname);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// Check if rom drive exists and activate it
|
|
|
+bool scsiDiskActivateRomDrive()
|
|
|
+{
|
|
|
+ uint32_t maxsize = azplatform_get_romdrive_maxsize() - AZPLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
+ azlog("-- Platform supports ROM drive up to ", (int)(maxsize / 1024), " kB");
|
|
|
+
|
|
|
+ romdrive_hdr_t hdr = {};
|
|
|
+ if (!check_romdrive(&hdr))
|
|
|
+ {
|
|
|
+ azlog("---- ROM drive image not detected");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (s2s_getConfigById(hdr.scsi_id))
|
|
|
+ {
|
|
|
+ azlog("---- ROM drive SCSI id ", (int)hdr.scsi_id, " is already in use, not enabling");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ azlog("---- Activating ROM drive, SCSI id ", (int)hdr.scsi_id, " size ", (int)(hdr.imagesize / 1024), " kB");
|
|
|
+ bool status = scsiDiskOpenHDDImage(hdr.scsi_id, "ROM:", hdr.scsi_id, 0, hdr.blocksize, hdr.drivetype);
|
|
|
+
|
|
|
+ if (!status)
|
|
|
+ {
|
|
|
+ azlog("---- ROM drive activation failed");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/***********************/
|
|
|
/* Backing image files */
|
|
|
/***********************/
|
|
|
@@ -58,12 +197,16 @@ SdDevice sdDev = {2, 256 * 1024 * 1024 * 2}; /* For SCSI2SD */
|
|
|
//
|
|
|
// Raw access is activated by using filename like "RAW:0:12345"
|
|
|
// where the numbers are the first and last sector.
|
|
|
+//
|
|
|
+// If the platform supports a ROM drive, it is activated by using
|
|
|
+// filename "ROM:".
|
|
|
class ImageBackingStore
|
|
|
{
|
|
|
public:
|
|
|
ImageBackingStore()
|
|
|
{
|
|
|
m_israw = false;
|
|
|
+ m_isrom = false;
|
|
|
m_blockdev = nullptr;
|
|
|
m_bgnsector = m_endsector = m_cursector = 0;
|
|
|
}
|
|
|
@@ -92,6 +235,17 @@ public:
|
|
|
m_endsector = sectorCount - 1;
|
|
|
}
|
|
|
}
|
|
|
+ else if (strncasecmp(filename, "ROM:", 4) == 0)
|
|
|
+ {
|
|
|
+ if (!check_romdrive(&m_romhdr))
|
|
|
+ {
|
|
|
+ m_romhdr.imagesize = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ m_isrom = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
m_fsfile = SD.open(filename, O_RDWR);
|
|
|
@@ -126,7 +280,16 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- bool isOpen() { return m_israw ? !!m_blockdev : m_fsfile.isOpen(); }
|
|
|
+ bool isOpen()
|
|
|
+ {
|
|
|
+ if (m_israw)
|
|
|
+ return (m_blockdev != NULL);
|
|
|
+ else if (m_isrom)
|
|
|
+ return (m_romhdr.imagesize > 0);
|
|
|
+ else
|
|
|
+ return m_fsfile.isOpen();
|
|
|
+ }
|
|
|
+
|
|
|
bool close()
|
|
|
{
|
|
|
if (m_israw)
|
|
|
@@ -134,6 +297,11 @@ public:
|
|
|
m_blockdev = nullptr;
|
|
|
return true;
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ m_romhdr.imagesize = 0;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.close();
|
|
|
@@ -146,6 +314,10 @@ public:
|
|
|
{
|
|
|
return (uint64_t)(m_endsector - m_bgnsector + 1) * SD_SECTOR_SIZE;
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ return m_romhdr.imagesize;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.size();
|
|
|
@@ -160,6 +332,12 @@ public:
|
|
|
*endSector = m_endsector;
|
|
|
return true;
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ *bgnSector = 0;
|
|
|
+ *endSector = 0;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.contiguousRange(bgnSector, endSector);
|
|
|
@@ -168,13 +346,20 @@ public:
|
|
|
|
|
|
bool seek(uint64_t pos)
|
|
|
{
|
|
|
- if (m_israw && m_blockdev)
|
|
|
+ if (m_israw)
|
|
|
{
|
|
|
uint32_t sectornum = pos / SD_SECTOR_SIZE;
|
|
|
assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
|
|
|
m_cursector = m_bgnsector + sectornum;
|
|
|
return (m_cursector <= m_endsector);
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ uint32_t sectornum = pos / SD_SECTOR_SIZE;
|
|
|
+ assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
|
|
|
+ m_cursector = sectornum;
|
|
|
+ return m_cursector * SD_SECTOR_SIZE < m_romhdr.imagesize;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.seek(pos);
|
|
|
@@ -197,6 +382,21 @@ public:
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ uint32_t sectorcount = count / SD_SECTOR_SIZE;
|
|
|
+ assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
|
|
|
+ uint32_t start = m_cursector * SD_SECTOR_SIZE + AZPLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
+ if (azplatform_read_romdrive((uint8_t*)buf, start, count))
|
|
|
+ {
|
|
|
+ m_cursector += sectorcount;
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.read(buf, count);
|
|
|
@@ -219,6 +419,11 @@ public:
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
+ else if (m_isrom)
|
|
|
+ {
|
|
|
+ azlog("ERROR: attempted to write to ROM drive");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
return m_fsfile.write(buf, count);
|
|
|
@@ -227,7 +432,7 @@ public:
|
|
|
|
|
|
void flush()
|
|
|
{
|
|
|
- if (!m_israw)
|
|
|
+ if (!m_israw && !m_isrom)
|
|
|
{
|
|
|
m_fsfile.flush();
|
|
|
}
|
|
|
@@ -235,6 +440,8 @@ public:
|
|
|
|
|
|
private:
|
|
|
bool m_israw;
|
|
|
+ bool m_isrom;
|
|
|
+ romdrive_hdr_t m_romhdr;
|
|
|
FsFile m_fsfile;
|
|
|
SdCard *m_blockdev;
|
|
|
uint32_t m_bgnsector;
|
|
|
@@ -438,7 +645,7 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
|
|
|
}
|
|
|
|
|
|
uint32_t sector_begin = 0, sector_end = 0;
|
|
|
- if (img.file.contiguousRange(§or_begin, §or_end))
|
|
|
+ if (img.file.contiguousRange(§or_begin, §or_end) && sector_end != 0)
|
|
|
{
|
|
|
azlog("---- Image file is contiguous, SD card sectors ", (int)sector_begin, " to ", (int)sector_end);
|
|
|
}
|