gctf2023/pwn/flipper/dist/common/source/fs/BDVirtualDevice.cpp

126 lines
3.8 KiB
C++
Raw Normal View History

2023-11-24 18:11:34 +00:00
#include "ArchInterrupts.h"
#include "BDDriver.h"
#include "BDRequest.h"
#include "BDVirtualDevice.h"
#include "kstring.h"
#include "debug.h"
#include "kprintf.h"
BDVirtualDevice::BDVirtualDevice(BDDriver * driver, uint32 offset, uint32 num_sectors, uint32 sector_size,
const char *name, bool writable) :
offset_(offset), num_sectors_(num_sectors), sector_size_(sector_size), block_size_(sector_size),
writable_(writable), driver_(driver), partition_type_(0), name_(name)
{
debug(BD_VIRT_DEVICE, "ctor: offset = %d, num_sectors = %d,\n sector_size = %d, "
"name = %s \n",
offset, num_sectors, sector_size, name);
dev_number_ = 0;
}
void BDVirtualDevice::addRequest(BDRequest * command)
{
command->setResult(5);
switch (command->getCmd())
{
case BDRequest::BD_GET_BLK_SIZE:
command->setResult(block_size_);
command->setStatus(BDRequest::BD_DONE);
break;
case BDRequest::BD_GET_NUM_BLOCKS:
command->setResult(getNumBlocks());
command->setStatus(BDRequest::BD_DONE);
break;
case BDRequest::BD_READ:
case BDRequest::BD_WRITE:
//start block and num blocks will be interpreted as start sector and num sectors
command->setStartBlock(command->getStartBlock() * (block_size_ / sector_size_) + offset_);
command->setNumBlocks(command->getNumBlocks() * (block_size_ / sector_size_));
// fall-through
default:
command->setResult(driver_->addRequest(command));
break;
}
return;
}
int32 BDVirtualDevice::readData(uint32 offset, uint32 size, char *buffer)
{
assert(buffer);
assert(offset % block_size_ == 0 && "we can only read multiples of block_size_ from the device");
assert(size % block_size_ == 0 && "we can only read multiples of block_size_ from the device");
assert((offset + size <= getNumBlocks() * block_size_) && "tried reading out of range");
debug(BD_VIRT_DEVICE, "readData\n");
uint32 blocks2read = size / block_size_, jiffies = 0;
uint32 blockoffset = offset / block_size_;
debug(BD_VIRT_DEVICE, "blocks2read %d\n", blocks2read);
BDRequest bd(dev_number_, BDRequest::BD_READ, blockoffset, blocks2read, buffer);
addRequest(&bd);
if (driver_->irq != 0)
{
bool interrupt_context = ArchInterrupts::disableInterrupts();
ArchInterrupts::enableInterrupts();
while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT)
ArchInterrupts::yieldIfIFSet();
if (!interrupt_context)
ArchInterrupts::disableInterrupts();
}
if (bd.getStatus() != BDRequest::BD_DONE)
{
return -1;
}
return size;
}
int32 BDVirtualDevice::writeData(uint32 offset, uint32 size, char *buffer)
{
assert(offset % block_size_ == 0 && "we can only write multiples of block_size_ to the device");
assert(size % block_size_ == 0 && "we can only write multiples of block_size_ to the device");
assert((offset + size <= getNumBlocks() * block_size_) && "tried writing out of range");
debug(BD_VIRT_DEVICE, "writeData\n");
uint32 blocks2write = size / block_size_, jiffies = 0;
uint32 blockoffset = offset / block_size_;
BDRequest bd(dev_number_, BDRequest::BD_WRITE, blockoffset, blocks2write, buffer);
addRequest(&bd);
if (driver_->irq != 0)
{
bool interrupt_context = ArchInterrupts::disableInterrupts();
ArchInterrupts::enableInterrupts();
while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT)
ArchInterrupts::yieldIfIFSet();
if (!interrupt_context)
ArchInterrupts::disableInterrupts();
}
if (bd.getStatus() != BDRequest::BD_DONE)
return -1;
else
return size;
}
void BDVirtualDevice::setPartitionType(uint8 part_type)
{
partition_type_ = part_type;
}
uint8 BDVirtualDevice::getPartitionType(void) const
{
return partition_type_;
}