[Denali] Add identify device command.
This commit is contained in:
parent
81469496d1
commit
d90c8eb1ef
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -33,7 +33,7 @@ glcr::ErrorOr<glcr::UniquePtr<AhciController>> AhciController::Init(
|
|||
return driver;
|
||||
}
|
||||
|
||||
glcr::ErrorOr<AhciDevice*> AhciController::GetDevice(uint64_t id) {
|
||||
glcr::ErrorOr<AhciPort*> 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<uint64_t>(ahci_hba_) + 0x100 + (0x80 * i);
|
||||
AhciPort* port = reinterpret_cast<AhciPort*>(port_addr);
|
||||
AhciPortHba* port = reinterpret_cast<AhciPortHba*>(port_addr);
|
||||
if ((port->sata_status & 0x103) != 0x103) {
|
||||
continue;
|
||||
}
|
||||
|
||||
devices_[i] = new AhciDevice(reinterpret_cast<AhciPort*>(port_addr));
|
||||
devices_[i]->DumpInfo();
|
||||
devices_[i] = new AhciPort(reinterpret_cast<AhciPortHba*>(port_addr));
|
||||
|
||||
if (devices_[i]->IsSata()) {
|
||||
IdentifyDeviceCommand identify(devices_[i].get());
|
||||
devices_[i]->IssueCommand(&identify);
|
||||
identify.WaitComplete();
|
||||
}
|
||||
}
|
||||
return glcr::OK;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <ztypes.h>
|
||||
|
||||
#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<AhciDevice*> GetDevice(uint64_t id);
|
||||
glcr::ErrorOr<AhciPort*> 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<AhciDevice> devices_[32];
|
||||
glcr::UniquePtr<AhciPort> devices_[32];
|
||||
|
||||
Thread irq_thread_;
|
||||
uint64_t irq_port_cap_ = 0;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "ahci/ahci_device.h"
|
||||
#include "ahci/ahci_port.h"
|
||||
|
||||
#include <glacier/status/error.h>
|
||||
#include <mammoth/util/debug.h>
|
||||
#include <zcall.h>
|
||||
|
||||
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);
|
|
@ -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;
|
|
@ -1,5 +1,7 @@
|
|||
#include "ahci/command.h"
|
||||
|
||||
#include <mammoth/util/debug.h>
|
||||
|
||||
#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<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),
|
||||
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<uint8_t>(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(); }
|
||||
|
|
|
@ -1,17 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <mammoth/sync/semaphore.h>
|
||||
#include <mammoth/util/memory_region.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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_;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ glcr::ErrorOr<glcr::UniquePtr<DenaliServer>> 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.");
|
||||
|
|
Loading…
Reference in New Issue