Make ATA commands use shared memory instead of allocating/deallocating objects every time

This commit is contained in:
StrikerX3 2019-01-13 15:09:57 -02:00
parent c5f0363c61
commit 23d81bce64
13 changed files with 95 additions and 19 deletions

View file

@ -0,0 +1,74 @@
#pragma once
#include <cstdlib>
namespace vixen {
/*!
* A reusable block of memory that dynamically resizes to accomodate the
* largest data structure written to it.
*
* Constructors and destructors are automatically invoked.
*/
class SharedMemory {
public:
SharedMemory() {}
~SharedMemory() {
if (m_dtor != nullptr) {
m_dtor(*this);
}
if (m_memory != nullptr) {
free(m_memory);
}
}
/*!
* Reserves memory for the given data structure, invoking the constructor
* with the given arguments. Placement new is used to initialize the object
* or value directly into the allocated memory block.
*
* If another data structure is currently occupying the shared memory, it
* will be destructed before reserving memory for the new data structure.
*
* If the new data structure is larger than the currently allocated memory
* block, a new block will be allocated with the new data structure size,
* otherwise the existing memory block is reused.
*/
template<class T, typename... Args>
T* Allocate(Args... args) {
// Invoke destructor from previous data structure
if (m_dtor != nullptr) {
m_dtor(*this);
}
// Reallocate memory if new data structure is larger than the current buffer
if (m_size < sizeof(T)) {
if (m_memory != nullptr) {
free(m_memory);
}
m_memory = malloc(sizeof(T));
m_size = sizeof(T);
}
// Update destructor to new data structure and call constructor
m_dtor = [](SharedMemory& u) { ((T*)u.m_memory)->~T(); };
return new(m_memory) T(args...);
}
/*!
* Destructs the data structure present in the shared memory, if any.
*/
void Free() {
if (m_dtor != nullptr) {
m_dtor(*this);
m_dtor = nullptr;
}
}
private:
void *m_memory = nullptr;
size_t m_size = 0;
void (*m_dtor)(SharedMemory&) = nullptr;
};
}

View file

@ -137,7 +137,7 @@ bool ATAChannel::WriteControlPort(uint32_t value, uint8_t size) {
log_debug("ATAChannel::WriteControlPort: Software reset triggered on channel %d\n", m_channel);
// TODO: implement [9.3.1] for device 0 and [9.3.2] for device 1
if (m_currentCommand != nullptr) {
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
}
}
@ -159,7 +159,7 @@ void ATAChannel::ReadData(uint32_t *value, uint8_t size) {
m_currentCommand->ReadData((uint8_t*)value, size);
if (m_currentCommand->IsFinished()) {
//log_spew("ATAChannel::ReadData: Finished processing command for channel %d\n", m_channel);
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
}
}
@ -183,7 +183,7 @@ void ATAChannel::WriteData(uint32_t value, uint8_t size) {
m_currentCommand->WriteData((uint8_t*)&value, size);
if (m_currentCommand->IsFinished()) {
//log_spew("ATAChannel::WriteData: Finished processing command for channel %d\n", m_channel);
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
}
}
@ -217,7 +217,7 @@ void ATAChannel::WriteCommand(uint8_t value) {
// Instantiate the command
auto factory = kCmdFactories.at(cmd);
m_currentCommand = factory(*dev);
m_currentCommand = factory(m_currentCommandMem, *dev);
// Every protocol starts by setting BSY=1
m_regs.status |= StBusy;
@ -227,7 +227,7 @@ void ATAChannel::WriteCommand(uint8_t value) {
m_currentCommand->Execute();
if (m_currentCommand->IsFinished()) {
//log_spew("ATAChannel::WriteCommand: Finished processing command 0x%x for channel %d, device %d\n", cmd, m_channel, devIndex);
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
}
}
@ -246,7 +246,7 @@ DMATransferResult ATAChannel::ReadDMA(uint8_t *dstBuffer, uint32_t readLen) {
m_currentCommand->ReadData(dstBuffer, readLen);
if (m_currentCommand->IsFinished()) {
//log_spew("ATAChannel::ReadDMA: Finished processing command for channel %d\n", m_channel);
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
return DMATransferEnd;
}
@ -267,7 +267,7 @@ DMATransferResult ATAChannel::WriteDMA(uint8_t *srcBuffer, uint32_t writeLen) {
m_currentCommand->WriteData(srcBuffer, writeLen);
if (m_currentCommand->IsFinished()) {
//log_spew("ATAChannel::WriteDMA: Finished processing command for channel %d\n", m_channel);
delete m_currentCommand;
m_currentCommandMem.Free();
m_currentCommand = nullptr;
return DMATransferEnd;
}

View file

@ -16,6 +16,7 @@
#include <mutex>
#include "vixen/cpu.h"
#include "vixen/shared_memory.h"
#include "../basic/irq.h"
#include "../basic/interrupt.h"
#include "ata_device.h"
@ -106,6 +107,7 @@ private:
bool m_interrupt = false; // [5.2.9] INTRQ (Device Interrupt)
SharedMemory m_currentCommandMem;
cmd::IATACommand *m_currentCommand;
std::mutex m_commandMutex;

View file

@ -13,6 +13,7 @@
#include <cstdint>
#include "vixen/shared_memory.h"
#include "../ata_device.h"
namespace vixen {
@ -62,7 +63,7 @@ public:
/*!
* Defines the factory function type used to build a factory table.
*/
typedef IATACommand* (*Factory)(ATADevice& device);
typedef IATACommand* (*Factory)(SharedMemory& sharedMemory, ATADevice& device);
protected:
ATADevice& m_device;

View file

@ -28,7 +28,7 @@ public:
IdentifyDevice(ATADevice& device);
virtual ~IdentifyDevice() override;
static IATACommand *Factory(ATADevice& device) { return new IdentifyDevice(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<IdentifyDevice, ATADevice&>(device); }
protected:
bool HasMoreData() override;

View file

@ -28,7 +28,7 @@ public:
IdentifyPacketDevice(ATADevice& device);
virtual ~IdentifyPacketDevice() override;
static IATACommand *Factory(ATADevice& device) { return new IdentifyPacketDevice(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<IdentifyPacketDevice, ATADevice&>(device); }
protected:
bool HasMoreData() override;

View file

@ -28,7 +28,7 @@ public:
InitializeDeviceParameters(ATADevice& device);
virtual ~InitializeDeviceParameters() override;
static IATACommand *Factory(ATADevice& device) { return new InitializeDeviceParameters(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<InitializeDeviceParameters, ATADevice&>(device); }
protected:
bool ExecuteImpl() override;

View file

@ -28,7 +28,7 @@ public:
Packet(ATADevice& device);
virtual ~Packet() override;
static IATACommand *Factory(ATADevice& device) { return new Packet(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<Packet, ATADevice&>(device); }
};
}

View file

@ -28,7 +28,7 @@ public:
ReadDMA(ATADevice& device);
virtual ~ReadDMA() override;
static IATACommand *Factory(ATADevice& device) { return new ReadDMA(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<ReadDMA, ATADevice&>(device); }
};
}

View file

@ -28,7 +28,7 @@ public:
SecurityUnlock(ATADevice& device);
virtual ~SecurityUnlock() override;
static IATACommand *Factory(ATADevice& device) { return new SecurityUnlock(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<SecurityUnlock, ATADevice&>(device); }
protected:
bool Initialize() override;

View file

@ -28,7 +28,7 @@ public:
SetFeatures(ATADevice& device);
virtual ~SetFeatures() override;
static IATACommand *Factory(ATADevice& device) { return new SetFeatures(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<SetFeatures, ATADevice&>(device); }
protected:
bool ExecuteImpl() override;

View file

@ -28,7 +28,7 @@ public:
WriteDMA(ATADevice& device);
virtual ~WriteDMA() override;
static IATACommand *Factory(ATADevice& device) { return new WriteDMA(device); }
static IATACommand *Factory(SharedMemory& sharedMemory, ATADevice& device) { return sharedMemory.Allocate<WriteDMA, ATADevice&>(device); }
};
}

View file

@ -28,12 +28,11 @@ NonDataProtocolCommand::~NonDataProtocolCommand() {
void NonDataProtocolCommand::Execute() {
bool successful = ExecuteImpl();
auto& regs = m_device.GetRegisters();
if (!successful) {
regs.status |= StError;
m_regs.status |= StError;
}
regs.status &= ~StBusy;
m_regs.status &= ~StBusy;
m_interrupt.Assert();
Finish();