From 7416429c55da2ae7962ac836f68039747b0a76d3 Mon Sep 17 00:00:00 2001 From: RaSCSI User Date: Sun, 13 Feb 2022 05:10:06 +0000 Subject: [PATCH] Added posix file i/o functionality --- src/raspberrypi/Makefile | 5 +- src/raspberrypi/devices/disk.cpp | 13 +- src/raspberrypi/devices/disk.h | 4 +- src/raspberrypi/devices/disk_track_cache.cpp | 174 ------ src/raspberrypi/devices/scsicd.cpp | 3 +- .../file_access/disk_track_cache.cpp | 576 ++++++++++++++++++ .../file_access/disk_track_cache.h | 88 +++ src/raspberrypi/file_access/file_access.cpp | 41 ++ .../file_access.h} | 37 +- .../file_access/file_access_factory.cpp | 49 ++ .../file_access/file_access_factory.h | 36 ++ .../file_access/mmap_file_access.cpp | 101 +++ .../file_access/mmap_file_access.h | 52 ++ .../file_access/posix_file_access.cpp | 106 ++++ .../file_access/posix_file_access.h | 41 ++ 15 files changed, 1116 insertions(+), 210 deletions(-) delete mode 100644 src/raspberrypi/devices/disk_track_cache.cpp create mode 100644 src/raspberrypi/file_access/disk_track_cache.cpp create mode 100644 src/raspberrypi/file_access/disk_track_cache.h create mode 100644 src/raspberrypi/file_access/file_access.cpp rename src/raspberrypi/{devices/disk_track_cache.h => file_access/file_access.h} (50%) create mode 100644 src/raspberrypi/file_access/file_access_factory.cpp create mode 100644 src/raspberrypi/file_access/file_access_factory.h create mode 100644 src/raspberrypi/file_access/mmap_file_access.cpp create mode 100644 src/raspberrypi/file_access/mmap_file_access.h create mode 100644 src/raspberrypi/file_access/posix_file_access.cpp create mode 100644 src/raspberrypi/file_access/posix_file_access.h diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index e3c47d87..4ede6e67 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -104,6 +104,7 @@ SRC_RASCSI = \ localizer.cpp SRC_RASCSI += $(shell find ./controllers -name '*.cpp') SRC_RASCSI += $(shell find ./devices -name '*.cpp') +SRC_RASCSI += $(shell find ./file_access -name '*.cpp') SRC_RASCSI += $(SRC_PROTOBUF) SRC_SCSIMON = \ @@ -139,8 +140,8 @@ SRC_SASIDUMP = \ fileio.cpp\ rascsi_version.cpp -vpath %.h ./ ./controllers ./devices ./monitor -vpath %.cpp ./ ./controllers ./devices ./monitor +vpath %.h ./ ./controllers ./devices ./file_access ./monitor +vpath %.cpp ./ ./controllers ./devices ./file_access ./monitor vpath %.o ./$(OBJDIR) vpath ./$(BINDIR) diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index bd5c2946..f9200efb 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -22,6 +22,7 @@ #include "disk.h" #include #include "../rascsi.h" +#include "file_access/file_access_factory.h" Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockCommands() { @@ -76,7 +77,7 @@ Disk::~Disk() if (IsReady()) { // Only if ready... if (disk.dcache) { - // disk.dcache->Save(); + disk.dcache->Save(); } } @@ -128,7 +129,7 @@ void Disk::Open(const Filepath& path) // Cache initialization assert (!disk.dcache); - disk.dcache = new DiskCache(path, disk.size, disk.blocks, disk.image_offset); + disk.dcache = FileAccessFactory::CreateFileAccess(path, disk.size, disk.blocks, disk.image_offset); // Can read/write open Fileio fio; @@ -517,8 +518,8 @@ void Disk::PreventAllowMediumRemoval(SASIDEV *controller) void Disk::SynchronizeCache10(SASIDEV *controller) { - // Flush the RaSCSI cache - // disk.dcache->Save(); + //Flush the RaSCSI cache + disk.dcache->Save(); controller->Status(); } @@ -544,7 +545,7 @@ bool Disk::Eject(bool force) bool status = Device::Eject(force); if (status) { // Remove disk cache - // disk.dcache->Save(); + disk.dcache->Save(); delete disk.dcache; disk.dcache = NULL; @@ -1295,7 +1296,7 @@ bool Disk::StartStop(const DWORD *cdb) if (!start) { // Flush the cache when stopping - // disk.dcache->Save(); + disk.dcache->Save(); // Look at the eject bit and eject if necessary if (load) { diff --git a/src/raspberrypi/devices/disk.h b/src/raspberrypi/devices/disk.h index 5760908f..4736bee9 100644 --- a/src/raspberrypi/devices/disk.h +++ b/src/raspberrypi/devices/disk.h @@ -22,7 +22,7 @@ #include "controllers/scsidev_ctrl.h" #include "device.h" #include "device_factory.h" -#include "disk_track_cache.h" +#include "file_access/file_access.h" #include "file_support.h" #include "filepath.h" #include @@ -51,7 +51,7 @@ private: uint32_t size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) // TODO blocks should be a 64 bit value in order to support higher capacities uint32_t blocks; // Total number of sectors - DiskCache *dcache; // Disk cache + FileAccess *dcache; // Disk cache off_t image_offset; // Offset to actual data } disk_t; diff --git a/src/raspberrypi/devices/disk_track_cache.cpp b/src/raspberrypi/devices/disk_track_cache.cpp deleted file mode 100644 index 2fb78caa..00000000 --- a/src/raspberrypi/devices/disk_track_cache.cpp +++ /dev/null @@ -1,174 +0,0 @@ -//--------------------------------------------------------------------------- -// -// X68000 EMULATOR "XM6" -// -// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) -// Copyright (C) 2014-2020 GIMONS -// -// XM6i -// Copyright (C) 2010-2015 isaki@NetBSD.org -// Copyright (C) 2010 Y.Sugahara -// -// Imported sava's Anex86/T98Next image and MO format support patch. -// Imported NetBSD support and some optimisation patch by Rin Okuyama. -// Comments translated to english by akuker. -// -// [ DiskTrack and DiskCache ] -// -//--------------------------------------------------------------------------- - -#include "os.h" -#include "log.h" -#include "fileio.h" -#include "disk_track_cache.h" -#include -#include - -//=========================================================================== -// -// Disk Cache -// -//=========================================================================== - -DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff) -{ - ASSERT(blocks > 0); - ASSERT(imgoff >= 0); - - initialized = false; - - // Other - serial = 0; - sec_path = path; - sec_size = size; - sec_blocks = blocks; - cd_raw = FALSE; - imgoffset = imgoff; - - fd = open(path.GetPath(), O_RDWR); - if(fd < 0){ - LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno) - } - struct stat sb; - if(fstat(fd, &sb) < 0){ - LOGWARN("Unable to run fstat. Errno:%d", errno); - } - printf("Size: %llu\n", (uint64_t)sb.st_size); - - // int x = EACCES; - - memory_block = (const char*)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - int errno_val = errno; - if (memory_block == MAP_FAILED) { - LOGWARN("Unabled to memory map file %s", path.GetPath()); - LOGWARN(" Errno:%d", errno_val); - errno_val = EACCES; - } - - - initialized = true; - -} - -DiskCache::~DiskCache() -{ - munmap((void*)memory_block, sb.st_size); - close(fd); - // Clear the track - // Clear(); -} - -void DiskCache::SetRawMode(BOOL raw) -{ - // Configuration - cd_raw = raw; -} - - -bool DiskCache::ReadSector(BYTE *buf, int block) -{ - ASSERT(sec_size != 0); - ASSERT(buf); - ASSERT(block < sec_blocks); - ASSERT(memory_block); - - if(!initialized){ - return false; - } - - int sector_size_bytes = (off_t)1 << sec_size; - - // Calculate offset into the image file - off_t offset = GetTrackOffset(block); - offset += GetSectorOffset(block); - LOGWARN("%s track:%d sector:%d offset:%llu block:%d size:%d", __PRETTY_FUNCTION__, (block >>8), (block & 0xff), offset, block, sector_size_bytes); - - // LOGINFO("Reading data track:%d sec_size:%d block:%d offset: %lld imgoffset: %lld", track, sec_size, block, offset, imgoffset); - - memcpy(buf, &memory_block[offset], sector_size_bytes); - - return true; - -} - -bool DiskCache::WriteSector(const BYTE *buf, int block) -{ - ASSERT(buf); - ASSERT(block < sec_blocks); - ASSERT(memory_block); - - if(!initialized){ - return false; - } - - int sector_size_bytes = (off_t)1 << sec_size; - - // Calculate offset into the image file - off_t offset = GetTrackOffset(block); - offset += GetSectorOffset(block); - LOGWARN("%s track:%d sector:%d offset:%llu block:%d size:%d", __PRETTY_FUNCTION__, (block >>8), (block & 0xff), offset, block, sector_size_bytes); - - memcpy((void*)&memory_block[offset], buf, sector_size_bytes); - - return true; -} - - -off_t DiskCache::GetSectorOffset(int block){ - - int sector_num = block & 0xff; - - // // // Error if the number of sectors exceeds the valid number - // if (sector_num >= sectors) { - // return false; - // } - - return (off_t)sector_num << sec_size; -} - -off_t DiskCache::GetTrackOffset(int block){ - - // Assuming that all tracks hold 256 sectors - int track_num = block >> 8; - - // Calculate offset (previous tracks are considered to hold 256 sectors) - off_t offset = ((off_t)track_num << 8); - if (cd_raw) { - ASSERT(sec_size == 11); - offset *= 0x930; - offset += 0x10; - } else { - offset <<= sec_size; - } - - // Add offset to real image - offset += imgoffset; - - return offset; -} - -// off_t DiskCache::GetTrackSize(){ -// // Calculate length (data size of this track) -// off_t length = sectors << sec_size; -// return length; -// } diff --git a/src/raspberrypi/devices/scsicd.cpp b/src/raspberrypi/devices/scsicd.cpp index e5fa05c9..f3f766f3 100644 --- a/src/raspberrypi/devices/scsicd.cpp +++ b/src/raspberrypi/devices/scsicd.cpp @@ -19,6 +19,7 @@ #include "exceptions.h" #include #include "../rascsi.h" +#include "file_access/file_access_factory.h" //=========================================================================== // @@ -599,7 +600,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block) // Recreate the disk cache Filepath path; track[index]->GetPath(path); - disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), GetBlockCount()); + disk.dcache = FileAccessFactory::CreateFileAccess(path, GetSectorSizeShiftCount(), GetBlockCount()); disk.dcache->SetRawMode(rawfile); // Reset data index diff --git a/src/raspberrypi/file_access/disk_track_cache.cpp b/src/raspberrypi/file_access/disk_track_cache.cpp new file mode 100644 index 00000000..fc35875d --- /dev/null +++ b/src/raspberrypi/file_access/disk_track_cache.cpp @@ -0,0 +1,576 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// Copyright (C) 2010 Y.Sugahara +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Imported NetBSD support and some optimisation patch by Rin Okuyama. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache ] +// +//--------------------------------------------------------------------------- + +#include "os.h" +#include "log.h" +#include "fileio.h" +#include "disk_track_cache.h" + +//=========================================================================== +// +// Disk Track +// +//=========================================================================== + +DiskTrack::DiskTrack() +{ + // Initialization of internal information + dt.track = 0; + dt.size = 0; + dt.sectors = 0; + dt.raw = FALSE; + dt.init = FALSE; + dt.changed = FALSE; + dt.length = 0; + dt.buffer = NULL; + dt.maplen = 0; + dt.changemap = NULL; + dt.imgoffset = 0; +} + +DiskTrack::~DiskTrack() +{ + // Release memory, but do not save automatically + if (dt.buffer) { + free(dt.buffer); + dt.buffer = NULL; + } + if (dt.changemap) { + free(dt.changemap); + dt.changemap = NULL; + } +} + +void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff) +{ + ASSERT(track >= 0); + ASSERT((sectors > 0) && (sectors <= 0x100)); + ASSERT(imgoff >= 0); + + // Set Parameters + dt.track = track; + dt.size = size; + dt.sectors = sectors; + dt.raw = raw; + + // Not initialized (needs to be loaded) + dt.init = FALSE; + + // Not Changed + dt.changed = FALSE; + + // Offset to actual data + dt.imgoffset = imgoff; +} + +bool DiskTrack::Load(const Filepath& path) +{ + // Not needed if already loaded + if (dt.init) { + ASSERT(dt.buffer); + ASSERT(dt.changemap); + return true; + } + + // Calculate offset (previous tracks are considered to hold 256 sectors) + off_t offset = ((off_t)dt.track << 8); + if (dt.raw) { + ASSERT(dt.size == 11); + offset *= 0x930; + offset += 0x10; + } else { + offset <<= dt.size; + } + + // Add offset to real image + offset += dt.imgoffset; + + // Calculate length (data size of this track) + int length = dt.sectors << dt.size; + + // Allocate buffer memory + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + + if (dt.buffer == NULL) { + if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { + LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); + } + dt.length = length; + } + + if (!dt.buffer) { + return false; + } + + // Reallocate if the buffer length is different + if (dt.length != (DWORD)length) { + free(dt.buffer); + if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { + LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); + } + dt.length = length; + } + + // Reserve change map memory + if (dt.changemap == NULL) { + dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); + dt.maplen = dt.sectors; + } + + if (!dt.changemap) { + return false; + } + + // Reallocate if the buffer length is different + if (dt.maplen != (DWORD)dt.sectors) { + free(dt.changemap); + dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); + dt.maplen = dt.sectors; + } + + // Clear changemap + memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); + + // Read from File + Fileio fio; + if (!fio.OpenDIO(path, Fileio::ReadOnly)) { + return false; + } + if (dt.raw) { + // Split Reading + for (int i = 0; i < dt.sectors; i++) { + // Seek + if (!fio.Seek(offset)) { + fio.Close(); + return false; + } + + // Read + if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) { + fio.Close(); + return false; + } + + // Next offset + offset += 0x930; + } + } else { + // Continuous reading + if (!fio.Seek(offset)) { + fio.Close(); + return false; + } + if (!fio.Read(dt.buffer, length)) { + fio.Close(); + return false; + } + } + fio.Close(); + + // Set a flag and end normally + dt.init = TRUE; + dt.changed = FALSE; + return true; +} + +bool DiskTrack::Save(const Filepath& path) +{ + // Not needed if not initialized + if (!dt.init) { + return true; + } + + // Not needed unless changed + if (!dt.changed) { + return true; + } + + // Need to write + ASSERT(dt.buffer); + ASSERT(dt.changemap); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + + // Writing in RAW mode is not allowed + ASSERT(!dt.raw); + + // Calculate offset (previous tracks are considered to hold 256 sectors) + off_t offset = ((off_t)dt.track << 8); + offset <<= dt.size; + + // Add offset to real image + offset += dt.imgoffset; + + // Calculate length per sector + int length = 1 << dt.size; + + // Open file + Fileio fio; + if (!fio.Open(path, Fileio::ReadWrite)) { + return false; + } + + // Partial write loop + int total; + for (int i = 0; i < dt.sectors;) { + // If changed + if (dt.changemap[i]) { + // Initialize write size + total = 0; + + // Seek + if (!fio.Seek(offset + ((off_t)i << dt.size))) { + fio.Close(); + return false; + } + + // Consectutive sector length + int j; + for (j = i; j < dt.sectors; j++) { + // end when interrupted + if (!dt.changemap[j]) { + break; + } + + // Add one sector + total += length; + } + + // Write + if (!fio.Write(&dt.buffer[i << dt.size], total)) { + fio.Close(); + return false; + } + + // To unmodified sector + i = j; + } else { + // Next Sector + i++; + } + } + + // Close + fio.Close(); + + // Drop the change flag and exit + memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); + dt.changed = FALSE; + return true; +} + +bool DiskTrack::ReadSector(BYTE *buf, int sec) const +{ + ASSERT(buf); + ASSERT((sec >= 0) & (sec < 0x100)); + + LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec); + // Error if not initialized + if (!dt.init) { + return false; + } + + // // Error if the number of sectors exceeds the valid number + if (sec >= dt.sectors) { + return false; + } + + // Copy + ASSERT(dt.buffer); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size); + + // Success + return true; +} + +bool DiskTrack::WriteSector(const BYTE *buf, int sec) +{ + ASSERT(buf); + ASSERT((sec >= 0) & (sec < 0x100)); + ASSERT(!dt.raw); + + // Error if not initialized + if (!dt.init) { + return false; + } + + // // Error if the number of sectors exceeds the valid number + if (sec >= dt.sectors) { + return false; + } + + // Calculate offset and length + int offset = sec << dt.size; + int length = 1 << dt.size; + + // Compare + ASSERT(dt.buffer); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + if (memcmp(buf, &dt.buffer[offset], length) == 0) { + // Exit normally since it's attempting to write the same thing + return true; + } + + // Copy, change + memcpy(&dt.buffer[offset], buf, length); + dt.changemap[sec] = TRUE; + dt.changed = TRUE; + + // Success + return true; +} + +//=========================================================================== +// +// Disk Cache +// +//=========================================================================== + +DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff) +{ + ASSERT(blocks > 0); + ASSERT(imgoff >= 0); + + // Cache work + for (int i = 0; i < CacheMax; i++) { + cache[i].disktrk = NULL; + cache[i].serial = 0; + } + +} + +DiskCache::~DiskCache() +{ + // Clear the track + Clear(); +} + +bool DiskCache::Save() +{ + // Save track + for (int i = 0; i < CacheMax; i++) { + // Is it a valid track? + if (cache[i].disktrk) { + // Save + if (!cache[i].disktrk->Save(sec_path)) { + return false; + } + } + } + + return true; +} + +//--------------------------------------------------------------------------- +// +// Get disk cache information +// +//--------------------------------------------------------------------------- +bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const +{ + ASSERT((index >= 0) && (index < CacheMax)); + + // false if unused + if (!cache[index].disktrk) { + return false; + } + + // Set track and serial + track = cache[index].disktrk->GetTrack(); + aserial = cache[index].serial; + + return true; +} + +void DiskCache::Clear() +{ + // Free the cache + for (int i = 0; i < CacheMax; i++) { + if (cache[i].disktrk) { + delete cache[i].disktrk; + cache[i].disktrk = NULL; + } + } +} + +bool DiskCache::ReadSector(BYTE *buf, int block) +{ + ASSERT(sec_size != 0); + + // Update first + UpdateSerialNumber(); + + // Calculate track (fixed to 256 sectors/track) + int track = block >> 8; + + // Get the track data + DiskTrack *disktrk = Assign(track); + if (!disktrk) { + return false; + } + + // Read the track data to the cache + return disktrk->ReadSector(buf, block & 0xff); +} + +bool DiskCache::WriteSector(const BYTE *buf, int block) +{ + ASSERT(sec_size != 0); + + // Update first + UpdateSerialNumber(); + + // Calculate track (fixed to 256 sectors/track) + int track = block >> 8; + + // Get that track data + DiskTrack *disktrk = Assign(track); + if (!disktrk) { + return false; + } + + // Write the data to the cache + return disktrk->WriteSector(buf, block & 0xff); +} + +//--------------------------------------------------------------------------- +// +// Track Assignment +// +//--------------------------------------------------------------------------- +DiskTrack* DiskCache::Assign(int track) +{ + ASSERT(sec_size != 0); + ASSERT(track >= 0); + + // First, check if it is already assigned + for (int i = 0; i < CacheMax; i++) { + if (cache[i].disktrk) { + if (cache[i].disktrk->GetTrack() == track) { + // Track match + cache[i].serial = serial; + return cache[i].disktrk; + } + } + } + + // Next, check for empty + for (int i = 0; i < CacheMax; i++) { + if (!cache[i].disktrk) { + // Try loading + if (Load(i, track)) { + // Success loading + cache[i].serial = serial; + return cache[i].disktrk; + } + + // Load failed + return NULL; + } + } + + // Finally, find the youngest serial number and delete it + + // Set index 0 as candidate c + DWORD s = cache[0].serial; + int c = 0; + + // Compare candidate with serial and update to smaller one + for (int i = 0; i < CacheMax; i++) { + ASSERT(cache[i].disktrk); + + // Compare and update the existing serial + if (cache[i].serial < s) { + s = cache[i].serial; + c = i; + } + } + + // Save this track + if (!cache[c].disktrk->Save(sec_path)) { + return NULL; + } + + // Delete this track + DiskTrack *disktrk = cache[c].disktrk; + cache[c].disktrk = NULL; + + if (Load(c, track, disktrk)) { + // Successful loading + cache[c].serial = serial; + return cache[c].disktrk; + } + + // Load failed + return NULL; +} + +//--------------------------------------------------------------------------- +// +// Load cache +// +//--------------------------------------------------------------------------- +bool DiskCache::Load(int index, int track, DiskTrack *disktrk) +{ + ASSERT((index >= 0) && (index < CacheMax)); + ASSERT(track >= 0); + ASSERT(!cache[index].disktrk); + + // Get the number of sectors on this track + int sectors = sec_blocks - (track << 8); + ASSERT(sectors > 0); + if (sectors > 0x100) { + sectors = 0x100; + } + + // Create a disk track + if (disktrk == NULL) { + disktrk = new DiskTrack(); + } + + // Initialize disk track + disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset); + + // Try loading + if (!disktrk->Load(sec_path)) { + // Failure + delete disktrk; + return false; + } + + // Allocation successful, work set + cache[index].disktrk = disktrk; + + return true; +} + +void DiskCache::UpdateSerialNumber() +{ + // Update and do nothing except 0 + serial++; + if (serial != 0) { + return; + } + + // Clear serial of all caches (loop in 32bit) + for (int i = 0; i < CacheMax; i++) { + cache[i].serial = 0; + } +} + diff --git a/src/raspberrypi/file_access/disk_track_cache.h b/src/raspberrypi/file_access/disk_track_cache.h new file mode 100644 index 00000000..91323329 --- /dev/null +++ b/src/raspberrypi/file_access/disk_track_cache.h @@ -0,0 +1,88 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache ] +// +//--------------------------------------------------------------------------- + +#pragma once + +#include "../rascsi.h" +#include "filepath.h" +#include "file_access/file_access.h" + +// Number of tracks to cache +#define CacheMax 16 + +class DiskTrack +{ +private: + struct { + int track; // Track Number + int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) + int sectors; // Number of sectors(<0x100) + DWORD length; // Data buffer length + BYTE *buffer; // Data buffer + BOOL init; // Is it initilized? + BOOL changed; // Changed flag + DWORD maplen; // Changed map length + BOOL *changemap; // Changed map + BOOL raw; // RAW mode flag + off_t imgoffset; // Offset to actual data + } dt; + +public: + DiskTrack(); + ~DiskTrack(); + + void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0); + bool Load(const Filepath& path); + bool Save(const Filepath& path); + + // Read / Write + bool ReadSector(BYTE *buf, int sec) const; // Sector Read + bool WriteSector(const BYTE *buf, int sec); // Sector Write + + int GetTrack() const { return dt.track; } // Get track +}; + +class DiskCache : public FileAccess +{ +public: + // Internal data definition + typedef struct { + DiskTrack *disktrk; // Disk Track + DWORD serial; // Serial + } cache_t; + +public: + DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); + ~DiskCache(); + + // Access + bool Save() override; // Save and release all + bool ReadSector(BYTE *buf, int block) override; // Sector Read + bool WriteSector(const BYTE *buf, int block) override; // Sector Write + bool GetCache(int index, int& track, DWORD& serial) const override; // Get cache information + +private: + // Internal Management + void Clear(); // Clear all tracks + DiskTrack* Assign(int track); // Load track + bool Load(int index, int track, DiskTrack *disktrk = NULL); // Load track + void UpdateSerialNumber(); // Update serial number + + // Internal data + cache_t cache[CacheMax]; // Cache management +}; + diff --git a/src/raspberrypi/file_access/file_access.cpp b/src/raspberrypi/file_access/file_access.cpp new file mode 100644 index 00000000..1d4522c9 --- /dev/null +++ b/src/raspberrypi/file_access/file_access.cpp @@ -0,0 +1,41 @@ + #include "file_access.h" + +FileAccess::FileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff){ + + serial = 0; + sec_path = path; + sec_size = size; + sec_blocks = blocks; + imgoffset = imgoff; +} +FileAccess::~FileAccess(){ + +} + + +off_t FileAccess::GetSectorOffset(int block){ + + int sector_num = block & 0xff; + return (off_t)sector_num << sec_size; +} + +off_t FileAccess::GetTrackOffset(int block){ + + // Assuming that all tracks hold 256 sectors + int track_num = block >> 8; + + // Calculate offset (previous tracks are considered to hold 256 sectors) + off_t offset = ((off_t)track_num << 8); + if (cd_raw) { + ASSERT(sec_size == 11); + offset *= 0x930; + offset += 0x10; + } else { + offset <<= sec_size; + } + + // Add offset to real image + offset += imgoffset; + + return offset; +} diff --git a/src/raspberrypi/devices/disk_track_cache.h b/src/raspberrypi/file_access/file_access.h similarity index 50% rename from src/raspberrypi/devices/disk_track_cache.h rename to src/raspberrypi/file_access/file_access.h index 074279e3..f4462c6c 100644 --- a/src/raspberrypi/devices/disk_track_cache.h +++ b/src/raspberrypi/file_access/file_access.h @@ -20,43 +20,30 @@ #include "../rascsi.h" #include "filepath.h" -class DiskCache +class FileAccess { - public: - DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); - ~DiskCache(); + FileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); + virtual ~FileAccess(); - void SetRawMode(BOOL raw); // CD-ROM raw mode setting + void SetRawMode(bool raw) { cd_raw = raw; }; // CD-ROM raw mode setting // Access - // bool Save(); // Save and release all - bool ReadSector(BYTE *buf, int block); // Sector Read - bool WriteSector(const BYTE *buf, int block); // Sector Write - // bool GetCache(int index, int& track, DWORD& serial) const; // Get cache information + virtual bool Save() = 0; // Save and release all + virtual bool ReadSector(BYTE *buf, int block) = 0; // Sector Read + virtual bool WriteSector(const BYTE *buf, int block) = 0; // Sector Write + virtual bool GetCache(int index, int& track, DWORD& serial) const = 0; // Get cache information -private: - // Internal Management - // void Clear(); // Clear all tracks - // DiskTrack* Assign(int track); // Load track - // bool Load(int index, int track, DiskTrack *disktrk = NULL); // Load track - // void UpdateSerialNumber(); // Update serial number - - // Internal data - // cache_t cache[CacheMax]; // Cache management +protected: + bool cd_raw = false; DWORD serial; // Last serial number Filepath sec_path; // Path + int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) int sec_blocks; // Blocks per sector - BOOL cd_raw; // CD-ROM RAW mode off_t imgoffset; // Offset to actual data - bool initialized; - - const char *memory_block; - struct stat sb; - int fd; - + off_t GetTrackOffset(int block); off_t GetSectorOffset(int block); }; diff --git a/src/raspberrypi/file_access/file_access_factory.cpp b/src/raspberrypi/file_access/file_access_factory.cpp new file mode 100644 index 00000000..94bb676c --- /dev/null +++ b/src/raspberrypi/file_access/file_access_factory.cpp @@ -0,0 +1,49 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache ] +// +//--------------------------------------------------------------------------- + +#include "file_access/file_access_factory.h" +#include "log.h" +#include "file_access/disk_track_cache.h" +#include "file_access/mmap_file_access.h" +#include "file_access/posix_file_access.h" + +FileAccessType FileAccessFactory::current_access_type = FileAccessType::ePosixFile; + +FileAccess *FileAccessFactory::CreateFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff){ + + FileAccess *result = NULL; + + if (current_access_type == FileAccessType::eMmapFile){ + LOGINFO("%s Creating MmapFileAccess %s", __PRETTY_FUNCTION__, path.GetPath()) + result = new MmapFileAccess(path, size, blocks, imgoff); + } + else if(current_access_type == FileAccessType::eRamCache) { + LOGINFO("%s Creating DiskCache %s", __PRETTY_FUNCTION__, path.GetPath()) + result = new DiskCache(path, size, blocks, imgoff); + } + else if(current_access_type == FileAccessType::ePosixFile) { + LOGINFO("%s Creating PosixFileAccess %s", __PRETTY_FUNCTION__, path.GetPath()) + result = new PosixFileAccess(path, size, blocks, imgoff); + } + + if (result == NULL){ + LOGWARN("%s Unable to create the File Access", __PRETTY_FUNCTION__); + } + return result; + +} + diff --git a/src/raspberrypi/file_access/file_access_factory.h b/src/raspberrypi/file_access/file_access_factory.h new file mode 100644 index 00000000..1cb5d593 --- /dev/null +++ b/src/raspberrypi/file_access/file_access_factory.h @@ -0,0 +1,36 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache ] +// +//--------------------------------------------------------------------------- + +#include "file_access/file_access.h" + +enum FileAccessType { + eRamCache, + eMmapFile, + ePosixFile, +}; + +class FileAccessFactory +{ +public: + static void SetFileAccessMethod(FileAccessType method) { current_access_type = method; }; + static FileAccessType GetFileAccessMethod() { return current_access_type; }; + + static FileAccess *CreateFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); + +private: + static FileAccessType current_access_type; +}; \ No newline at end of file diff --git a/src/raspberrypi/file_access/mmap_file_access.cpp b/src/raspberrypi/file_access/mmap_file_access.cpp new file mode 100644 index 00000000..bfb541b8 --- /dev/null +++ b/src/raspberrypi/file_access/mmap_file_access.cpp @@ -0,0 +1,101 @@ +//--------------------------------------------------------------------------- +// +// Copyright (C) 2022 akuker +// +// This method of file access will use the mmap() capabilities to 'map' the +// file into memory. +// +// This doesn't actually copy the file into RAM, but instead maps the file +// as virtual memory. Behind the scenes, the file is still being accessed. +// +// The operating system will do some caching of the data to prevent direct +// drive access for each read/write. So, instead of implementing our own +// caching mechanism (like in disk_track_cache.h), we just rely on the +// operating system. +// +// [ MmapFileAccess ] +// +//--------------------------------------------------------------------------- + +#include "mmap_file_access.h" +#include "log.h" +#include +#include +#include + +//=========================================================================== +// +// Direct file access that will map the file into virtual memory space +// +//=========================================================================== +MmapFileAccess::MmapFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff) +{ + ASSERT(blocks > 0); + ASSERT(imgoff >= 0); + + fd = open(path.GetPath(), O_RDWR); + if(fd < 0){ + LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno) + } + LOGWARN("%s opened %s", __PRETTY_FUNCTION__, path.GetPath()); + struct stat sb; + if(fstat(fd, &sb) < 0){ + LOGWARN("Unable to run fstat. Errno:%d", errno); + } + printf("Size: %llu\n", (uint64_t)sb.st_size); + + LOGWARN("%s mmap-ed file of size: %llu", __PRETTY_FUNCTION__, (uint64_t)sb.st_size); + + // int x = EACCES; + + memory_block = (const char*)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + int errno_val = errno; + if (memory_block == MAP_FAILED) { + LOGWARN("Unabled to memory map file %s", path.GetPath()); + LOGWARN(" Errno:%d", errno_val); + return; + } + initialized = true; +} + +MmapFileAccess::~MmapFileAccess() +{ + munmap((void*)memory_block, sb.st_size); + close(fd); + + // Force the OS to save any cached data to the disk + sync(); +} + +bool MmapFileAccess::ReadSector(BYTE *buf, int block) +{ + ASSERT(sec_size != 0); + ASSERT(buf); + ASSERT(block < sec_blocks); + ASSERT(memory_block); + + int sector_size_bytes = (off_t)1 << sec_size; + + // Calculate offset into the image file + off_t offset = GetTrackOffset(block); + offset += GetSectorOffset(block); + + memcpy(buf, &memory_block[offset], sector_size_bytes); + + return true; +} + +bool MmapFileAccess::WriteSector(const BYTE *buf, int block) +{ + + ASSERT(buf); + ASSERT(block < sec_blocks); + ASSERT(memory_block); + + ASSERT((block * sec_size) <= (sb.st_size + sec_size)); + + memcpy((void*)&memory_block[(block * sec_size)], buf, sec_size); + + return true; +} + diff --git a/src/raspberrypi/file_access/mmap_file_access.h b/src/raspberrypi/file_access/mmap_file_access.h new file mode 100644 index 00000000..43d43a70 --- /dev/null +++ b/src/raspberrypi/file_access/mmap_file_access.h @@ -0,0 +1,52 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2022 akuker +// +// This method of file access will use the mmap() capabilities to 'map' the +// file into memory. +// +// This doesn't actually copy the file into RAM, but instead maps the file +// as virtual memory. Behind the scenes, the file is still being accessed. +// +// The operating system will do some caching of the data to prevent direct +// drive access for each read/write. So, instead of implementing our own +// caching mechanism (like in disk_track_cache.h), we just rely on the +// operating system. +// +// [ MmapFileAccess ] +// +//--------------------------------------------------------------------------- + +#pragma once + +#include "../rascsi.h" +#include "filepath.h" +#include "file_access/file_access.h" + +class MmapFileAccess : public FileAccess +{ + +public: + MmapFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); + ~MmapFileAccess(); + + void SetRawMode(BOOL raw); // CD-ROM raw mode setting + + // Access + bool Save() { return true; }; // Save and release all + bool ReadSector(BYTE *buf, int block); // Sector Read + bool WriteSector(const BYTE *buf, int block); // Sector Write + bool GetCache(int index, int& track, DWORD& serial) const { return true; }; // Get cache information + + +private: + const char *memory_block; + struct stat sb; + int fd; + + bool initialized = false; +}; + diff --git a/src/raspberrypi/file_access/posix_file_access.cpp b/src/raspberrypi/file_access/posix_file_access.cpp new file mode 100644 index 00000000..f8085b32 --- /dev/null +++ b/src/raspberrypi/file_access/posix_file_access.cpp @@ -0,0 +1,106 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2021 akuker +// +// [ PosixFileAccess ] +// +//--------------------------------------------------------------------------- + +#include "posix_file_access.h" +#include "log.h" +#include +#include +#include + +//=========================================================================== +// +// Direct file access that will map the file into virtual memory space +// +//=========================================================================== +PosixFileAccess::PosixFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff) : FileAccess(path, size, blocks, imgoff) +{ + ASSERT(blocks > 0); + ASSERT(imgoff >= 0); + + + fd = open(path.GetPath(), O_RDWR); + if(fd < 0){ + LOGWARN("Unable to open file %s. Errno:%d", path.GetPath(), errno) + return; + } + struct stat sb; + if(fstat(fd, &sb) < 0){ + LOGWARN("Unable to run fstat. Errno:%d", errno); + return; + } + + LOGWARN("%s opened file of size: %llu", __PRETTY_FUNCTION__, (uint64_t)sb.st_size); + + initialized = true; +} + +PosixFileAccess::~PosixFileAccess() +{ + close(fd); + + // Force the OS to save any cached data to the disk + sync(); +} + +bool PosixFileAccess::ReadSector(BYTE *buf, int block) +{ + if(!initialized){ + return false; + } + + ASSERT(sec_size != 0); + ASSERT(buf); + ASSERT(block < sec_blocks); + ASSERT(memory_block); + + size_t sector_size_bytes = (size_t)1 << sec_size; + + // Calculate offset into the image file + off_t offset = GetTrackOffset(block); + offset += GetSectorOffset(block); + + lseek(fd, offset, SEEK_SET); + size_t result = read(fd, buf,sector_size_bytes); + if(result != sector_size_bytes){ + LOGWARN("%s only read %d bytes but wanted %d ", __PRETTY_FUNCTION__, result, sector_size_bytes); + } + + return true; +} + +bool PosixFileAccess::WriteSector(const BYTE *buf, int block) +{ + if(!initialized){ + return false; + } + + ASSERT(buf); + ASSERT(block < sec_blocks); + ASSERT(memory_block); + + ASSERT((block * sec_size) <= (sb.st_size + sec_size)); + + size_t sector_size_bytes = (size_t)1 << sec_size; + + off_t offset = GetTrackOffset(block); + offset += GetSectorOffset(block); + + + lseek(fd, offset, SEEK_SET); + size_t result = write(fd, buf,sector_size_bytes); + if(result != sector_size_bytes){ + LOGWARN("%s only wrote %d bytes but wanted %d ", __PRETTY_FUNCTION__, result, sector_size_bytes); + } + + return true; +} + + diff --git a/src/raspberrypi/file_access/posix_file_access.h b/src/raspberrypi/file_access/posix_file_access.h new file mode 100644 index 00000000..8c126f80 --- /dev/null +++ b/src/raspberrypi/file_access/posix_file_access.h @@ -0,0 +1,41 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2021 akuker +// +// [ PosixFileAccess ] +// +//--------------------------------------------------------------------------- + +#pragma once + +#include "filepath.h" +#include "file_access/file_access.h" + +class PosixFileAccess : public FileAccess +{ + +public: + PosixFileAccess(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); + ~PosixFileAccess(); + + void SetRawMode(BOOL raw); // CD-ROM raw mode setting + + // Access + bool Save() { return true; }; // Save and release all + bool ReadSector(BYTE *buf, int block); // Sector Read + bool WriteSector(const BYTE *buf, int block); // Sector Write + bool GetCache(int index, int& track, DWORD& serial) const { return true; }; // Get cache information + + +private: + + + int fd; + + bool initialized = false; + +}; +