From b8b6576b7f62b7d48589bf50fa83079c8280e669 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 12 Jun 2023 23:32:24 -0700 Subject: [PATCH] Cleanup AHCI Ident a bit and reduce logging --- sys/denali/ahci/ahci.h | 105 +++++++++++++++++++++++++++++--- sys/denali/ahci/ahci_device.cpp | 81 ++++++++++++++++++------ sys/denali/ahci/ahci_device.h | 17 ++++-- sys/denali/ahci/ahci_driver.cpp | 45 +++++--------- sys/denali/ahci/ahci_driver.h | 8 ++- zion/boot/acpi.cpp | 2 +- zion/interrupt/apic.cpp | 2 +- zion/syscall/syscall.cpp | 3 - 8 files changed, 195 insertions(+), 68 deletions(-) diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 002a938..7ca9559 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -35,7 +35,7 @@ struct PciMsiCap { uint8_t reserved; uint64_t message_address; uint16_t message_data; -}; +} __attribute__((packed)); struct AhciHba { uint32_t capabilities; @@ -90,7 +90,7 @@ struct PhysicalRegionDescriptor { // 21:0 is byte count // 31 is Interrupt on Completion uint32_t byte_count; -}; +} __attribute__((packed)); struct CommandTable { uint8_t command_fis[64]; @@ -110,9 +110,73 @@ typedef enum { FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host } FIS_TYPE; -struct DmaFis {}; +struct DmaFis { + // DWORD 0 + uint8_t fis_type; // FIS_TYPE_DMA_SETUP + + uint8_t pmport : 4; // Port multiplier + uint8_t rsv0 : 1; // Reserved + uint8_t d : 1; // Data transfer direction, 1 - device to host + uint8_t i : 1; // Interrupt bit + uint8_t a : 1; // Auto-activate. Specifies if DMA Activate FIS is needed + + uint8_t rsved[2]; // Reserved + + // DWORD 1&2 + + uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer + // in host memory. SATA Spec says host specific and not + // in Spec. Trying AHCI spec might work. + + // DWORD 3 + uint32_t rsvd; // More reserved + + // DWORD 4 + uint32_t DMAbufOffset; // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + uint32_t TransferCount; // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + uint32_t resvd; // Reserved +} __attribute__((packed)); + +struct PioSetupFis { + // DWORD 0 + uint8_t fis_type; // FIS_TYPE_PIO_SETUP + + uint8_t pmport : 4; // Port multiplier + uint8_t rsv0 : 1; // Reserved + uint8_t d : 1; // Data transfer direction, 1 - device to host + uint8_t i : 1; // Interrupt bit + uint8_t rsv1 : 1; + + uint8_t status; // Status register + uint8_t error; // Error register + + // DWORD 1 + uint8_t lba0; // LBA low register, 7:0 + uint8_t lba1; // LBA mid register, 15:8 + uint8_t lba2; // LBA high register, 23:16 + uint8_t device; // Device register + + // DWORD 2 + uint8_t lba3; // LBA register, 31:24 + uint8_t lba4; // LBA register, 39:32 + uint8_t lba5; // LBA register, 47:40 + uint8_t rsv2; // Reserved + + // DWORD 3 + uint8_t countl; // Count register, 7:0 + uint8_t counth; // Count register, 15:8 + uint8_t rsv3; // Reserved + uint8_t e_status; // New value of status register + + // DWORD 4 + uint16_t tc; // Transfer count + uint8_t rsv4[2]; // Reserved +} __attribute__((packed)); -struct PioSetupFis {}; struct HostToDeviceRegisterFis { uint8_t fis_type; // FIS_TYPE_REG_H2D uint8_t pmp_and_c; @@ -138,9 +202,36 @@ struct HostToDeviceRegisterFis { // DWORD 4 uint32_t reserved; // Reserved -}; -struct DeviceToHostRegisterFis {}; -struct SetDeviceBitsFis {}; +} __attribute__((packed)); +struct DeviceToHostRegisterFis { + // DWORD 0 + uint8_t fis_type; // FIS_TYPE_REG_D2H + + uint8_t pmport_and_i; + + uint8_t status; // Status register + uint8_t error; // Error register + + // DWORD 1 + uint8_t lba0; // LBA low register, 7:0 + uint8_t lba1; // LBA mid register, 15:8 + uint8_t lba2; // LBA high register, 23:16 + uint8_t device; // Device register + + // DWORD 2 + uint8_t lba3; // LBA register, 31:24 + uint8_t lba4; // LBA register, 39:32 + uint8_t lba5; // LBA register, 47:40 + uint8_t reserved1; + + // DWORD 3 + uint16_t count; + uint16_t reserved2; + + uint32_t reserved3; +} __attribute__((packed)); +struct SetDeviceBitsFis { +} __attribute__((packed)); struct ReceivedFis { DmaFis dma_fis; diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index 6b0a2b7..c8e5d1d 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -4,6 +4,12 @@ #include #include +namespace { + +void HandleIdent(AhciDevice* dev) { dev->HandleIdentify(); } + +} // namespace + AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { if ((port_struct_->sata_status & 0x103) != 0x103) { return; @@ -15,27 +21,30 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { crash("Non adjacent cl & fis", Z_ERR_UNIMPLEMENTED); } - check(ZMemoryObjectCreatePhysical(cl_page, 0x1000, &vmmo_cap_)); - - uint64_t vaddr; - check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap_, &vaddr)); + command_structures_ = MappedMemoryRegion::DirectPhysical(cl_page, 0x1000); uint64_t cl_off = port_struct_->command_list_base & 0xFFF; - command_list_ = reinterpret_cast(vaddr + cl_off); + command_list_ = + reinterpret_cast(command_structures_.vaddr() + cl_off); uint64_t fis_off = port_struct_->fis_base & 0xFFF; - received_fis_ = reinterpret_cast(vaddr + fis_off); + received_fis_ = + reinterpret_cast(command_structures_.vaddr() + fis_off); // FIXME: Hacky uint64_t ct_off = command_list_->command_headers[0].command_table_base_addr & 0xFFF; - command_table_ = reinterpret_cast(vaddr + ct_off); + command_table_ = + reinterpret_cast(command_structures_.vaddr() + ct_off); - port_struct_->interrupt_status = 0; port_struct_->interrupt_enable = 0xFFFFFFFF; + + if (port_struct_->signature == 0x101) { + SendIdentify(); + } } -z_err_t AhciDevice::SendIdentify(uint16_t** result) { +z_err_t AhciDevice::SendIdentify() { HostToDeviceRegisterFis fis{ .fis_type = FIS_TYPE_REG_H2D, .pmp_and_c = 0x80, @@ -64,22 +73,24 @@ z_err_t AhciDevice::SendIdentify(uint16_t** result) { memcpy(command_table_->command_fis, &fis, sizeof(fis)); - port_struct_->command_issue |= 1; + commands_[0].region = MappedMemoryRegion::ContiguousPhysical(512); + commands_[0].callback = HandleIdent; - uint64_t vmmo_cap, paddr; - RET_ERR(ZMemoryObjectCreateContiguous(512, &vmmo_cap, &paddr)); - - command_table_->prds[0].region_address = paddr; + command_table_->prds[0].region_address = commands_[0].region.paddr(); command_table_->prds[0].byte_count = 512; - uint64_t vaddr; - RET_ERR(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap, &vaddr)); - - *result = reinterpret_cast(vaddr); + port_struct_->command_issue |= 1; + commands_issued_ |= 1; return Z_OK; } +void AhciDevice::HandleIdentify() { + dbgln("Handling Idenify"); + uint16_t* ident = reinterpret_cast(commands_[0].region.vaddr()); + dbgln("Ident: %x", ident[0]); +} + void AhciDevice::DumpInfo() { dbgln("Comlist: %lx", port_struct_->command_list_base); dbgln("FIS: %lx", port_struct_->fis_base); @@ -88,7 +99,6 @@ void AhciDevice::DumpInfo() { dbgln("SATA status: %x", port_struct_->sata_status); dbgln("Int status: %x", port_struct_->interrupt_status); dbgln("Int enable: %x", port_struct_->interrupt_enable); - dbgln("Int enable: %x", port_struct_->interrupt_enable); // Just dump one command info for now. for (uint64_t i = 0; i < 1; i++) { @@ -105,5 +115,36 @@ void AhciDevice::HandleIrq() { // FIXME: Probably only clear the interrupts we know how to handle. port_struct_->interrupt_status = int_status; - dbgln("int receieved: %x", int_status); + uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; + + for (uint64_t i = 0; i < 32; i++) { + if (commands_finished & (1 << i)) { + commands_[i].callback(this); + commands_issued_ &= ~(1 << i); + } + } + + // TODO: Do something with this information. + if (int_status & 0x1) { + // Device to host. + DeviceToHostRegisterFis& fis = received_fis_->device_to_host_register_fis; + if (fis.fis_type != FIS_TYPE_REG_D2H) { + dbgln("BAD FIS TYPE (exp,act): %x, %x", FIS_TYPE_REG_D2H, fis.fis_type); + return; + } + if (fis.error) { + dbgln("D2H err: %x", fis.error); + } + } + if (int_status & 0x2) { + // PIO. + PioSetupFis& fis = received_fis_->pio_set_fis; + if (fis.fis_type != FIS_TYPE_PIO_SETUP) { + dbgln("BAD FIS TYPE (exp,act): %x, %x", FIS_TYPE_PIO_SETUP, fis.fis_type); + return; + } + if (fis.error) { + dbgln("PIO err: %x", fis.error); + } + } } diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_device.h index 686818d..f815427 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_device.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "ahci/ahci.h" @@ -12,18 +13,26 @@ class AhciDevice { void DumpInfo(); - bool IsInit() { return port_struct_ != nullptr && vmmo_cap_ != 0; } + bool IsInit() { return port_struct_ != nullptr && command_structures_; } - // Result will point to a 512 byte (256 word array). - z_err_t SendIdentify(uint16_t** result); + z_err_t SendIdentify(); + void HandleIdentify(); void HandleIrq(); private: AhciPort* port_struct_ = nullptr; - uint64_t vmmo_cap_ = 0; + MappedMemoryRegion command_structures_; CommandList* command_list_ = nullptr; ReceivedFis* received_fis_ = nullptr; CommandTable* command_table_ = nullptr; + + struct Command { + typedef void (*Callback)(AhciDevice*); + MappedMemoryRegion region; + Callback callback; + }; + Command commands_[32]; + uint32_t commands_issued_ = 0; }; diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_driver.cpp index 96f7f9a..2b88a3c 100644 --- a/sys/denali/ahci/ahci_driver.cpp +++ b/sys/denali/ahci/ahci_driver.cpp @@ -23,17 +23,13 @@ void interrupt_thread(void* void_driver) { z_err_t AhciDriver::Init() { RET_ERR(LoadPciDeviceHeader()); - RET_ERR(LoadCapabilities()); - dbgln("ABAR: %x", pci_device_header_->abar); - dbgln("Interrupt line: %x", pci_device_header_->interrupt_line); - dbgln("Interrupt pin: %x", pci_device_header_->interrupt_pin); + // RET_ERR(LoadCapabilities()); RET_ERR(RegisterIrq()); RET_ERR(LoadHbaRegisters()); - dbgln("Version: %x", ahci_hba_->version); ahci_hba_->global_host_control |= kGhc_InteruptEnable; RET_ERR(LoadDevices()); - DumpCapabilities(); - DumpPorts(); + // DumpCapabilities(); + // DumpPorts(); return Z_OK; } @@ -41,8 +37,6 @@ void AhciDriver::DumpCapabilities() { dbgln("AHCI Capabilities:"); uint32_t caps = ahci_hba_->capabilities; - dbgln("Num Ports: %u", (caps & 0x1F) + 1); - dbgln("Num Command Slots: %u", ((caps & 0x1F00) >> 8) + 1); if (caps & 0x20) { dbgln("External SATA"); } @@ -134,21 +128,18 @@ void AhciDriver::InterruptLoop() { while (true) { uint64_t type, bytes, caps; check(ZPortRecv(irq_port_cap_, 0, 0, 0, 0, &type, &bytes, &caps)); - for (uint64_t i = 0; i < 6; i++) { - if (devices_[i].IsInit()) { + for (uint64_t i = 0; i < 32; i++) { + if (devices_[i].IsInit() && (ahci_hba_->interrupt_status & (1 << i))) { devices_[i].HandleIrq(); + ahci_hba_->interrupt_status &= ~(1 << i); } } } } z_err_t AhciDriver::LoadPciDeviceHeader() { - uint64_t vmmo_cap; - RET_ERR(ZMemoryObjectCreatePhysical(kSataPciPhys, kPciSize, &vmmo_cap)); - - uint64_t vaddr; - RET_ERR(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap, &vaddr)); - pci_device_header_ = reinterpret_cast(vaddr); + pci_region_ = MappedMemoryRegion::DirectPhysical(kSataPciPhys, kPciSize); + pci_device_header_ = reinterpret_cast(pci_region_.vaddr()); return Z_OK; } @@ -192,31 +183,23 @@ z_err_t AhciDriver::RegisterIrq() { } z_err_t AhciDriver::LoadHbaRegisters() { - uint64_t vmmo_cap; - RET_ERR( - ZMemoryObjectCreatePhysical(pci_device_header_->abar, 0x1100, &vmmo_cap)); + ahci_region_ = + MappedMemoryRegion::DirectPhysical(pci_device_header_->abar, 0x1100); + ahci_hba_ = reinterpret_cast(ahci_region_.vaddr()); + num_ports_ = (ahci_hba_->capabilities & 0x1F) + 1; + num_commands_ = ((ahci_hba_->capabilities & 0x1F00) >> 8) + 1; - uint64_t vaddr; - RET_ERR(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap, &vaddr)); - ahci_hba_ = reinterpret_cast(vaddr); return Z_OK; } z_err_t AhciDriver::LoadDevices() { - // FIXME: Don't set this up so we hardcode 6 devices. - for (uint8_t i = 0; i < 6; i++) { + for (uint8_t i = 0; i < 32; i++) { if (!(ahci_hba_->port_implemented & (1 << i))) { continue; } uint64_t port_addr = reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); devices_[i] = AhciDevice(reinterpret_cast(port_addr)); - if (!devices_[i].IsInit()) { - continue; - } - dbgln("Identify %u", i); - uint16_t* identify; - devices_[i].SendIdentify(&identify); } return Z_OK; } diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_driver.h index 0cebe37..173790e 100644 --- a/sys/denali/ahci/ahci_driver.h +++ b/sys/denali/ahci/ahci_driver.h @@ -16,14 +16,20 @@ class AhciDriver { void DumpPorts(); private: + MappedMemoryRegion pci_region_; PciDeviceHeader* pci_device_header_ = nullptr; + MappedMemoryRegion ahci_region_; AhciHba* ahci_hba_ = nullptr; - AhciDevice devices_[6]; + // TODO: Allocate these dynamically. + AhciDevice devices_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; + uint64_t num_ports_; + uint64_t num_commands_; + z_err_t LoadPciDeviceHeader(); z_err_t LoadCapabilities(); z_err_t RegisterIrq(); diff --git a/zion/boot/acpi.cpp b/zion/boot/acpi.cpp index ae91bf2..57f332e 100644 --- a/zion/boot/acpi.cpp +++ b/zion/boot/acpi.cpp @@ -136,7 +136,6 @@ void ParseMcfg(SdtHeader* rsdt) { void ParseMadt(SdtHeader* rsdt) { #if K_ACPI_DEBUG dbgsz(rsdt->signature, 4); -#endif uint64_t max_addr = reinterpret_cast(rsdt) + rsdt->length; MadtHeader* header = reinterpret_cast(rsdt); @@ -180,6 +179,7 @@ void ParseMadt(SdtHeader* rsdt) { entry = reinterpret_cast(reinterpret_cast(entry) + entry->length); } +#endif } void ParseSdt(SdtHeader* rsdt) { diff --git a/zion/interrupt/apic.cpp b/zion/interrupt/apic.cpp index ff546e4..fe4f2da 100644 --- a/zion/interrupt/apic.cpp +++ b/zion/interrupt/apic.cpp @@ -7,7 +7,7 @@ #include "common/port.h" #include "debug/debug.h" -#define APIC_DEBUG 1 +#define APIC_DEBUG 0 namespace { diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 313095f..caabb95 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -187,7 +187,6 @@ z_err_t ChannelRecv(ZChannelRecvReq* req) { z_err_t PortRecv(ZPortRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); - dbgln("Port cap %u", req->port_cap); auto port_cap = proc.GetCapability(req->port_cap); RET_ERR(ValidateCap(port_cap, Capability::PORT, ZC_READ)); @@ -199,12 +198,10 @@ z_err_t IrqRegister(ZIrqRegisterReq* req, ZIrqRegisterResp* resp) { auto& proc = gScheduler->CurrentProcess(); if (req->irq_num != Z_IRQ_PCI_BASE) { // FIXME: Don't hardcode this nonsense. - dbgln("Irq %x", req->irq_num); return Z_ERR_UNIMPLEMENTED; } RefPtr port = MakeRefCounted(); resp->port_cap = proc.AddCapability(port); - dbgln("Port cap %u", resp->port_cap); RegisterPciPort(port); return Z_OK; }