From d90c8eb1ef02dd6e37d1406c9f24ea732905d9f9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:30:08 -0800 Subject: [PATCH] [Denali] Add identify device command. --- sys/denali/CMakeLists.txt | 2 +- sys/denali/ahci/ahci.h | 6 ++- sys/denali/ahci/ahci_controller.cpp | 13 +++-- sys/denali/ahci/ahci_controller.h | 6 +-- .../ahci/{ahci_device.cpp => ahci_port.cpp} | 21 ++++---- .../ahci/{ahci_device.h => ahci_port.h} | 13 ++--- sys/denali/ahci/command.cpp | 52 +++++++++++++++---- sys/denali/ahci/command.h | 36 ++++++++++--- sys/denali/denali_server.cpp | 4 +- 9 files changed, 109 insertions(+), 44 deletions(-) rename sys/denali/ahci/{ahci_device.cpp => ahci_port.cpp} (88%) rename sys/denali/ahci/{ahci_device.h => ahci_port.h} (72%) diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index ea177f3..566ab17 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,6 +1,6 @@ add_executable(denali - ahci/ahci_device.cpp ahci/ahci_controller.cpp + ahci/ahci_port.cpp ahci/command.cpp denali.cpp denali_server.cpp diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 320b5fd..c927de7 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -64,7 +64,7 @@ const uint32_t kInterrupt_DMA_FIS = (1 << 2); const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3); const uint32_t kInterrupt_Unknown_FIS = (1 << 4); -struct AhciPort { +struct AhciPortHba { uint64_t command_list_base; uint64_t fis_base; uint32_t interrupt_status; @@ -190,6 +190,9 @@ struct PioSetupFis { uint8_t rsv4[2]; // Reserved } __attribute__((packed)); +const uint8_t kIdentifyDevice = 0xEC; +const uint8_t kDmaReadExt = 0x25; + struct HostToDeviceRegisterFis { uint8_t fis_type; // FIS_TYPE_REG_H2D uint8_t pmp_and_c; @@ -216,6 +219,7 @@ struct HostToDeviceRegisterFis { // DWORD 4 uint32_t reserved; // Reserved } __attribute__((packed)); + struct DeviceToHostRegisterFis { // DWORD 0 uint8_t fis_type; // FIS_TYPE_REG_D2H diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index 1ee5712..67c7079 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -33,7 +33,7 @@ glcr::ErrorOr> AhciController::Init( return driver; } -glcr::ErrorOr AhciController::GetDevice(uint64_t id) { +glcr::ErrorOr AhciController::GetDevice(uint64_t id) { if (id >= num_ports_) { return glcr::INVALID_ARGUMENT; } @@ -237,13 +237,18 @@ glcr::ErrorCode AhciController::LoadDevices() { uint64_t port_addr = reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); - AhciPort* port = reinterpret_cast(port_addr); + AhciPortHba* port = reinterpret_cast(port_addr); if ((port->sata_status & 0x103) != 0x103) { continue; } - devices_[i] = new AhciDevice(reinterpret_cast(port_addr)); - devices_[i]->DumpInfo(); + devices_[i] = new AhciPort(reinterpret_cast(port_addr)); + + if (devices_[i]->IsSata()) { + IdentifyDeviceCommand identify(devices_[i].get()); + devices_[i]->IssueCommand(&identify); + identify.WaitComplete(); + } } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_controller.h b/sys/denali/ahci/ahci_controller.h index 69cb2cc..69ca9da 100644 --- a/sys/denali/ahci/ahci_controller.h +++ b/sys/denali/ahci/ahci_controller.h @@ -6,7 +6,7 @@ #include #include "ahci/ahci.h" -#include "ahci/ahci_device.h" +#include "ahci/ahci_port.h" class AhciController { public: @@ -16,7 +16,7 @@ class AhciController { void InterruptLoop(); - glcr::ErrorOr GetDevice(uint64_t id); + glcr::ErrorOr GetDevice(uint64_t id); void DumpCapabilities(); void DumpPorts(); @@ -27,7 +27,7 @@ class AhciController { mmth::OwnedMemoryRegion ahci_region_; volatile AhciHba* ahci_hba_ = nullptr; - glcr::UniquePtr devices_[32]; + glcr::UniquePtr devices_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_port.cpp similarity index 88% rename from sys/denali/ahci/ahci_device.cpp rename to sys/denali/ahci/ahci_port.cpp index 40513ff..add488e 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -1,10 +1,10 @@ -#include "ahci/ahci_device.h" +#include "ahci/ahci_port.h" #include #include #include -AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { +AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { if ((port_struct_->sata_status & 0x103) != 0x103) { crash("Creating device on port without a device", glcr::FAILED_PRECONDITION); @@ -34,14 +34,14 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { (paddr + 0x500) + (0x100 * i); commands_[i] = nullptr; } - port_struct_->interrupt_enable = - kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | - kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; + port_struct_->interrupt_enable = 0xFFFFFFFF; + // kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | + // kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; port_struct_->sata_error = -1; port_struct_->command |= kCommand_Start; } -glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { +glcr::ErrorCode AhciPort::IssueCommand(Command* command) { uint64_t slot; for (slot = 0; slot < 32; slot++) { if (commands_[slot] == nullptr) { @@ -56,7 +56,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { command->PopulatePrdt(command_tables_[slot].prdt); command_list_->command_headers[slot].command = - (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F | (1 << 7); command_list_->command_headers[slot].prd_table_length = 1; command_list_->command_headers[slot].prd_byte_count = 0; @@ -68,7 +68,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { return glcr::OK; } -void AhciDevice::DumpInfo() { +void AhciPort::DumpInfo() { dbgln("Comlist: {x}", port_struct_->command_list_base); dbgln("FIS: {x}", port_struct_->fis_base); dbgln("Command: {x}", port_struct_->command); @@ -88,7 +88,7 @@ bool CheckFisType(FIS_TYPE expected, uint8_t actual) { return false; } -void AhciDevice::HandleIrq() { +void AhciPort::HandleIrq() { uint32_t int_status = port_struct_->interrupt_status; port_struct_->interrupt_status = int_status; @@ -103,7 +103,9 @@ void AhciDevice::HandleIrq() { } if (fis.error) { dbgln("D2H err: {x}", fis.error); + dbgln("status: {x}", fis.status); + dbgln("Error: {x}", port_struct_->sata_error); has_error = true; } } @@ -114,6 +116,7 @@ void AhciDevice::HandleIrq() { if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { return; } + dbgln("Count: {x} {x} {x}", fis.counth, fis.countl, fis.e_status); if (fis.error) { dbgln("PIO err: {x}", fis.error); dbgln("status: {x}", fis.status); diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_port.h similarity index 72% rename from sys/denali/ahci/ahci_device.h rename to sys/denali/ahci/ahci_port.h index 49c36fe..e7e1a75 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_port.h @@ -8,25 +8,26 @@ #include "ahci/ahci.h" #include "ahci/command.h" -class AhciDevice { +class AhciPort { public: - AhciDevice() {} + AhciPort() {} // Caller retains ownership of the pointer. - AhciDevice(AhciPort* port_struct); + AhciPort(AhciPortHba* port_struct); void DumpInfo(); + bool IsSata() { return port_struct_->signature == 0x101; } bool IsInit() { return port_struct_ != nullptr && command_structures_; } glcr::ErrorCode IssueCommand(Command* command); void HandleIrq(); - AhciDevice(const AhciDevice&) = delete; - AhciDevice& operator=(const AhciDevice&) = delete; + AhciPort(const AhciPort&) = delete; + AhciPort& operator=(const AhciPort&) = delete; private: - volatile AhciPort* port_struct_ = nullptr; + volatile AhciPortHba* port_struct_ = nullptr; mmth::OwnedMemoryRegion command_structures_; volatile CommandList* command_list_ = nullptr; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index eea4ad0..8a1d388 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -1,5 +1,7 @@ #include "ahci/command.h" +#include + #include "ahci/ahci.h" namespace { @@ -17,12 +19,46 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} +void Command::SignalComplete() { + OnComplete(); + callback_semaphore_.Signal(); +} +void Command::WaitComplete() { callback_semaphore_.Wait(); } + +void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) { + 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) { + prdt[0].region_address = paddr_; + prdt[0].byte_count = 0x200 - 1; + dbgln("paddr: {x}", paddr_); + uint16_t* ident = reinterpret_cast(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(identify_.vaddr()); + uint32_t* sector_size = reinterpret_cast(ident + 117); + dbgln("Sector size: {}", *sector_size); + uint64_t* lbas = reinterpret_cast(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), - callback_semaphore_() {} + : lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {} DmaReadCommand::~DmaReadCommand() {} @@ -30,7 +66,7 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) { HostToDeviceRegisterFis fis{ .fis_type = FIS_TYPE_REG_H2D, .pmp_and_c = 0x80, - .command = 0x25, + .command = kDmaReadExt, .featurel = 0, .lba0 = static_cast(lba_ & 0xFF), @@ -50,14 +86,10 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) { .reserved = 0, }; - uint64_t bytes = sector_cnt_ * 512; - memcpy(command_fis, &fis, sizeof(fis)); } + void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { prdt[0].region_address = paddr_; prdt[0].byte_count = sector_cnt_ * 512; } - -void DmaReadCommand::SignalComplete() { callback_semaphore_.Signal(); } -void DmaReadCommand::WaitComplete() { callback_semaphore_.Wait(); } diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index 61fef58..b9a3c2d 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -1,17 +1,43 @@ #pragma once #include +#include #include #include "ahci/ahci.h" +class AhciPort; + class Command { public: + Command() = default; virtual ~Command(); virtual void PopulateFis(uint8_t* command_fis) = 0; virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; - virtual void WaitComplete() = 0; - virtual void SignalComplete() = 0; + void WaitComplete(); + void SignalComplete(); + + virtual void OnComplete() {} + + private: + // TODO: Make this owned by the device so that we don't have to create a new + // one with the kernel every time a command is issued. + mmth::Semaphore callback_semaphore_; +}; + +class IdentifyDeviceCommand : public Command { + public: + IdentifyDeviceCommand(AhciPort* port) : port_(port) {} + virtual void PopulateFis(uint8_t* command_fis) override; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; + + virtual void OnComplete() override; + + private: + AhciPort* port_; + uint64_t paddr_; + mmth::OwnedMemoryRegion identify_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_); }; class DmaReadCommand : public Command { @@ -23,14 +49,8 @@ class DmaReadCommand : public Command { void PopulateFis(uint8_t* command_fis) override; void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; - void WaitComplete() override; - void SignalComplete() override; - private: uint64_t lba_; uint64_t sector_cnt_; uint64_t paddr_; - // TODO: Make this owned by the device so that we don't have to create a new - // one with the kernel every time a command is issued. - mmth::Semaphore callback_semaphore_; }; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 0d433a0..db8eb0a 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -14,7 +14,7 @@ glcr::ErrorOr> DenaliServer::Create( glcr::Status DenaliServer::HandleRead(const ReadRequest& req, ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id())); + ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); uint64_t paddr; mmth::OwnedMemoryRegion region = @@ -33,7 +33,7 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id())); + ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); if (req.lba().size() != req.sector_cnt().size()) { return glcr::InvalidArgument("LBA and Sector Cnt must be the same length.");