[Denali] Add a simpler command method and use it to send identify.

This commit is contained in:
Drew Galbraith 2023-12-08 15:05:43 -08:00
parent e71017070f
commit 3e1da2bc90
4 changed files with 76 additions and 48 deletions

View File

@ -44,10 +44,21 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) {
glcr::ErrorCode AhciPort::Identify() {
if (IsSata()) {
IdentifyDeviceCommand identify(this);
CommandInfo identify{
.command = kIdentifyDevice,
.lba = 0,
.sectors = 1,
.paddr = 0,
};
auto region =
mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &identify.paddr);
ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify));
sem->Wait();
identify.OnComplete();
uint16_t* ident = reinterpret_cast<uint16_t*>(region.vaddr());
uint32_t* sector_size = reinterpret_cast<uint32_t*>(ident + 117);
dbgln("Sector size: {}", *sector_size);
uint64_t* lbas = reinterpret_cast<uint64_t*>(ident + 100);
dbgln("LBA Count: {}", *lbas);
}
return glcr::OK;
}
@ -77,6 +88,61 @@ glcr::ErrorOr<mmth::Semaphore*> AhciPort::IssueCommand(const Command& command) {
return &command_signals_[slot];
}
glcr::ErrorOr<mmth::Semaphore*> AhciPort::IssueCommand(
const CommandInfo& command) {
uint64_t slot;
for (slot = 0; slot < 32; slot++) {
if (!(commands_issued_ & (1 << slot))) {
break;
}
}
if (slot == 32) {
dbgln("All slots full");
return glcr::INTERNAL;
}
auto* fis = reinterpret_cast<HostToDeviceRegisterFis*>(
command_tables_[slot].command_fis);
*fis = HostToDeviceRegisterFis{
.fis_type = FIS_TYPE_REG_H2D,
.pmp_and_c = 0x80,
.command = command.command,
.featurel = 0,
.lba0 = static_cast<uint8_t>(command.lba & 0xFF),
.lba1 = static_cast<uint8_t>((command.lba >> 8) & 0xFF),
.lba2 = static_cast<uint8_t>((command.lba >> 16) & 0xFF),
.device = (1 << 6), // ATA LBA Mode
.lba3 = static_cast<uint8_t>((command.lba >> 24) & 0xFF),
.lba4 = static_cast<uint8_t>((command.lba >> 32) & 0xFF),
.lba5 = static_cast<uint8_t>((command.lba >> 40) & 0xFF),
.featureh = 0,
.count = command.sectors,
.icc = 0,
.control = 0,
.reserved = 0,
};
command_tables_[slot].prdt[0].region_address = command.paddr;
command_tables_[slot].prdt[0].byte_count = 512 * command.sectors;
command_list_->command_headers[slot].prd_table_length = 1;
command_list_->command_headers[slot].command =
(sizeof(HostToDeviceRegisterFis) / 2) & 0x1F;
// Set prefetch bit.
command_list_->command_headers[slot].command |= (1 << 7);
// TODO: Synchronization-wise we need to ensure this is set in the same
// critical section as where we select a slot.
commands_issued_ |= (1 << slot);
port_struct_->command_issue |= (1 << slot);
return &command_signals_[slot];
}
void AhciPort::DumpInfo() {
dbgln("Comlist: {x}", port_struct_->command_list_base);
dbgln("FIS: {x}", port_struct_->fis_base);

View File

@ -24,6 +24,7 @@ class AhciPort {
glcr::ErrorCode Identify();
glcr::ErrorOr<mmth::Semaphore*> IssueCommand(const Command& command);
glcr::ErrorOr<mmth::Semaphore*> IssueCommand(const CommandInfo& command);
void HandleIrq();

View File

@ -19,37 +19,6 @@ void* memcpy(void* dest, const void* src, uint64_t count) {
Command::~Command() {}
void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) const {
HostToDeviceRegisterFis fis __attribute__((aligned(16))){
.fis_type = FIS_TYPE_REG_H2D,
.pmp_and_c = 0x80,
.command = kIdentifyDevice,
.device = 0,
};
memcpy(command_fis, &fis, sizeof(fis));
}
void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const {
prdt[0].region_address = paddr_;
prdt[0].byte_count = 0x200 - 1;
dbgln("paddr: {x}", paddr_);
uint16_t* ident = reinterpret_cast<uint16_t*>(identify_.vaddr());
dbgln("vaddr: {x}", identify_.vaddr());
for (uint32_t i = 0; i < 256; i++) {
ident[i] = 0;
}
}
void IdentifyDeviceCommand::OnComplete() {
uint16_t* ident = reinterpret_cast<uint16_t*>(identify_.vaddr());
uint32_t* sector_size = reinterpret_cast<uint32_t*>(ident + 117);
dbgln("Sector size: {}", *sector_size);
uint64_t* lbas = reinterpret_cast<uint64_t*>(ident + 100);
dbgln("LBA Count: {}", *lbas);
// TODO tell the port its sector size.
}
DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt,
uint64_t paddr)
: lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {}

View File

@ -8,6 +8,13 @@
class AhciPort;
struct CommandInfo {
uint8_t command;
uint64_t lba;
uint16_t sectors;
uint64_t paddr;
};
class Command {
public:
Command() = default;
@ -16,21 +23,6 @@ class Command {
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const = 0;
};
class IdentifyDeviceCommand : public Command {
public:
IdentifyDeviceCommand(AhciPort* port) : port_(port) {}
virtual void PopulateFis(uint8_t* command_fis) const override;
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override;
void OnComplete();
private:
AhciPort* port_;
uint64_t paddr_;
mmth::OwnedMemoryRegion identify_ =
mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_);
};
class DmaReadCommand : public Command {
public:
DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr);