diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index 49d0355..6a0f268 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable(denali ahci/ahci_device.cpp ahci/ahci_driver.cpp + ahci/command.cpp denali.cpp denali_server.cpp ) diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 7ca9559..030df7f 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -96,7 +96,7 @@ struct CommandTable { uint8_t command_fis[64]; uint8_t atapi_command[16]; uint8_t reserved[48]; - PhysicalRegionDescriptor prds[65535]; + PhysicalRegionDescriptor prdt[65535]; } __attribute__((packed)); typedef enum { diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index a7d43f4..443107f 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -4,12 +4,6 @@ #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; @@ -38,59 +32,25 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { reinterpret_cast(command_structures_.vaddr() + ct_off); port_struct_->interrupt_enable = 0xFFFFFFFF; - - if (port_struct_->signature == 0x101) { - SendIdentify(); - } } -z_err_t AhciDevice::SendIdentify() { - HostToDeviceRegisterFis fis{ - .fis_type = FIS_TYPE_REG_H2D, - .pmp_and_c = 0x80, - .command = 0xEC, - .featurel = 0, +z_err_t AhciDevice::IssueCommand(Command* command) { + command->PopulateFis(command_table_->command_fis); + command->PopulatePrdt(command_table_->prdt); - .lba0 = 0, - .lba1 = 0, - .lba2 = 0, - .device = 0, - - .lba3 = 0, - .lba4 = 0, - .lba5 = 0, - .featureh = 0, - - .count = 0, - .icc = 0, - .control = 0, - - .reserved = 0, - }; - - command_list_->command_headers[0].command = (sizeof(fis) / 2) & 0x1F; + command_list_->command_headers[0].command = + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; command_list_->command_headers[0].prd_table_length = 1; + command_list_->command_headers[0].prd_byte_count = 0; - memcpy(command_table_->command_fis, &fis, sizeof(fis)); + commands_[0] = command; - commands_[0].region = MappedMemoryRegion::ContiguousPhysical(512); - // commands_[0].callback = HandleIdent; - - command_table_->prds[0].region_address = commands_[0].region.paddr(); - command_table_->prds[0].byte_count = 512; - - port_struct_->command_issue |= 1; commands_issued_ |= 1; + port_struct_->command_issue |= 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); @@ -116,11 +76,15 @@ void AhciDevice::HandleIrq() { port_struct_->interrupt_status = int_status; uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; + dbgln("finished %x", commands_finished); + dbgln("status %x", int_status); + dbgln("Issued %x, %x", commands_issued_, port_struct_->command_issue); + // FIXME: Pass error codes to the callback. for (uint64_t i = 0; i < 32; i++) { if (commands_finished & (1 << i)) { - // commands_[i].callback(this); commands_issued_ &= ~(1 << i); + commands_[i]->Callback(); } } @@ -134,6 +98,7 @@ void AhciDevice::HandleIrq() { } if (fis.error) { dbgln("D2H err: %x", fis.error); + dbgln("status: %x", fis.status); } } if (int_status & 0x2) { diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_device.h index b0ebe2b..16da0aa 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_device.h @@ -4,6 +4,7 @@ #include #include "ahci/ahci.h" +#include "ahci/command.h" class AhciDevice { public: @@ -15,11 +16,13 @@ class AhciDevice { bool IsInit() { return port_struct_ != nullptr && command_structures_; } - z_err_t SendIdentify(); - void HandleIdentify(); + z_err_t IssueCommand(Command* command); void HandleIrq(); + AhciDevice(const AhciDevice&) = delete; + AhciDevice& operator=(const AhciDevice&) = delete; + private: AhciPort* port_struct_ = nullptr; MappedMemoryRegion command_structures_; @@ -28,10 +31,6 @@ class AhciDevice { ReceivedFis* received_fis_ = nullptr; CommandTable* command_table_ = nullptr; - struct Command { - MappedMemoryRegion region; - // std::function callback; - }; - Command commands_[32]; - uint32_t commands_issued_ = 0; + Command* commands_[32]; + volatile uint32_t commands_issued_ = 0; }; diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_driver.cpp index 753caf0..27aafe1 100644 --- a/sys/denali/ahci/ahci_driver.cpp +++ b/sys/denali/ahci/ahci_driver.cpp @@ -33,16 +33,16 @@ z_err_t AhciDriver::Init() { return Z_OK; } -z_err_t AhciDriver::GetDevice(uint64_t id, AhciDevice& device) { +z_err_t AhciDriver::GetDevice(uint64_t id, AhciDevice** device) { if (id >= 32) { return Z_ERR_INVALID; } - if (!devices_[id].IsInit()) { + if (devices_[id] != nullptr && !devices_[id]->IsInit()) { return Z_ERR_NOT_FOUND; } - device = devices_[id]; + *device = devices_[id]; return Z_OK; } @@ -126,24 +126,27 @@ void AhciDriver::DumpCapabilities() { void AhciDriver::DumpPorts() { for (uint64_t i = 0; i < 6; i++) { - AhciDevice& dev = devices_[i]; - if (!dev.IsInit()) { + AhciDevice* dev = devices_[i]; + if (dev == nullptr || !dev->IsInit()) { continue; } dbgln(""); dbgln("Port %u:", i); - dev.DumpInfo(); + dev->DumpInfo(); } } void AhciDriver::InterruptLoop() { + dbgln("Starting interrupt loop"); 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 < 32; i++) { - if (devices_[i].IsInit() && (ahci_hba_->interrupt_status & (1 << i))) { - devices_[i].HandleIrq(); + if (devices_[i] != nullptr && devices_[i]->IsInit() && + (ahci_hba_->interrupt_status & (1 << i))) { + dbgln("Interrupt for %u", i); + devices_[i]->HandleIrq(); ahci_hba_->interrupt_status &= ~(1 << i); } } @@ -212,7 +215,7 @@ z_err_t AhciDriver::LoadDevices() { } uint64_t port_addr = reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); - devices_[i] = AhciDevice(reinterpret_cast(port_addr)); + devices_[i] = new AhciDevice(reinterpret_cast(port_addr)); } return Z_OK; } diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_driver.h index 5af934a..d89c510 100644 --- a/sys/denali/ahci/ahci_driver.h +++ b/sys/denali/ahci/ahci_driver.h @@ -12,7 +12,7 @@ class AhciDriver { void InterruptLoop(); - z_err_t GetDevice(uint64_t id, AhciDevice& device); + z_err_t GetDevice(uint64_t id, AhciDevice** device); void DumpCapabilities(); void DumpPorts(); @@ -24,7 +24,7 @@ class AhciDriver { AhciHba* ahci_hba_ = nullptr; // TODO: Allocate these dynamically. - AhciDevice devices_[32]; + AhciDevice* devices_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp new file mode 100644 index 0000000..1f13c25 --- /dev/null +++ b/sys/denali/ahci/command.cpp @@ -0,0 +1,49 @@ +#include "ahci/command.h" + +#include + +#include "ahci/ahci.h" + +Command::~Command() {} + +DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, + DmaCallback callback) + : lba_(lba), sector_cnt_(sector_cnt), callback_(callback) { + region_ = MappedMemoryRegion::ContiguousPhysical(sector_cnt * 512); +} + +DmaReadCommand::~DmaReadCommand() {} + +void DmaReadCommand::PopulateFis(uint8_t* command_fis) { + HostToDeviceRegisterFis fis{ + .fis_type = FIS_TYPE_REG_H2D, + .pmp_and_c = 0x80, + .command = 0x25, + .featurel = 0, + + .lba0 = static_cast(lba_ & 0xFF), + .lba1 = static_cast((lba_ >> 8) & 0xFF), + .lba2 = static_cast((lba_ >> 16) & 0xFF), + .device = (1 << 6), // ATA LBA Mode + + .lba3 = static_cast((lba_ >> 24) & 0xFF), + .lba4 = static_cast((lba_ >> 32) & 0xFF), + .lba5 = static_cast((lba_ >> 40) & 0xFF), + .featureh = 0, + + .count = static_cast(sector_cnt_), + .icc = 0, + .control = 0, + + .reserved = 0, + }; + + uint64_t bytes = sector_cnt_ * 512; + + memcpy(command_fis, &fis, sizeof(fis)); +} +void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { + prdt[0].region_address = region_.paddr(); + prdt[0].byte_count = region_.size(); +} +void DmaReadCommand::Callback() { callback_(lba_, sector_cnt_, region_.cap()); } diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h new file mode 100644 index 0000000..685b7d8 --- /dev/null +++ b/sys/denali/ahci/command.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "ahci/ahci.h" + +class Command { + public: + virtual ~Command(); + virtual void PopulateFis(uint8_t* command_fis) = 0; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; + virtual void Callback() = 0; +}; + +class DmaReadCommand : public Command { + public: + typedef void (*DmaCallback)(uint64_t, uint64_t, uint64_t); + DmaReadCommand(uint64_t lba, uint64_t sector_cnt, DmaCallback callback); + + virtual ~DmaReadCommand() override; + + void PopulateFis(uint8_t* command_fis) override; + void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; + + void Callback() override; + + private: + uint64_t lba_; + uint64_t sector_cnt_; + DmaCallback callback_; + MappedMemoryRegion region_; +}; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index b21049f..686032a 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -3,8 +3,17 @@ #include #include +namespace { +DenaliServer* gServer = nullptr; +void HandleResponse(uint64_t lba, uint64_t size, uint64_t cap) { + gServer->HandleResponse(lba, size, cap); +} +} // namespace + DenaliServer::DenaliServer(uint64_t channel_cap, AhciDriver& driver) - : channel_cap_(channel_cap), driver_(driver) {} + : channel_cap_(channel_cap), driver_(driver) { + gServer = this; +} z_err_t DenaliServer::RunServer() { while (true) { @@ -20,12 +29,7 @@ z_err_t DenaliServer::RunServer() { case DENALI_READ: { DenaliRead* read_req = reinterpret_cast(read_buffer_); uint64_t memcap = 0; - DenaliReadResponse resp; - RET_ERR(HandleRead(*read_req, resp, memcap)); - uint64_t caps_len = memcap ? 1 : 0; - RET_ERR(ZChannelSend(channel_cap_, 0, sizeof(DenaliReadResponse), - reinterpret_cast(&resp), caps_len, - &memcap)); + RET_ERR(HandleRead(*read_req)); break; } default: @@ -35,10 +39,22 @@ z_err_t DenaliServer::RunServer() { } } -z_err_t DenaliServer::HandleRead(const DenaliRead& read, - DenaliReadResponse& resp, uint64_t& memcap) { - AhciDevice device; - RET_ERR(driver_.GetDevice(read.device_id, device)); +z_err_t DenaliServer::HandleRead(const DenaliRead& read) { + AhciDevice* device; + RET_ERR(driver_.GetDevice(read.device_id, &device)); + + device->IssueCommand( + new DmaReadCommand(read.lba, read.size, ::HandleResponse)); return Z_OK; } + +void DenaliServer::HandleResponse(uint64_t lba, uint64_t size, uint64_t cap) { + DenaliReadResponse resp{ + .device_id = 0, + .lba = lba, + .size = size, + }; + check(ZChannelSend(channel_cap_, DENALI_READ, sizeof(resp), + reinterpret_cast(&resp), 1, &cap)); +} diff --git a/sys/denali/denali_server.h b/sys/denali/denali_server.h index dc2fedd..e1c1011 100644 --- a/sys/denali/denali_server.h +++ b/sys/denali/denali_server.h @@ -9,6 +9,8 @@ class DenaliServer { z_err_t RunServer(); + void HandleResponse(uint64_t lba, uint64_t size, uint64_t cap); + private: static const uint64_t kBuffSize = 1024; uint64_t channel_cap_; @@ -16,6 +18,5 @@ class DenaliServer { AhciDriver& driver_; - z_err_t HandleRead(const DenaliRead& read, DenaliReadResponse& resp, - uint64_t& mem_cap); + z_err_t HandleRead(const DenaliRead& read); }; diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp index 5a0e145..fcad96a 100644 --- a/sys/yellowstone/yellowstone.cpp +++ b/sys/yellowstone/yellowstone.cpp @@ -6,14 +6,34 @@ #include "hw/pcie.h" -uint64_t main() { +int main() { dbgln("Yellowstone Initializing."); uint64_t vaddr; check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, Z_INIT_BOOT_VMMO, &vaddr)); Channel local; check(SpawnProcessFromElfRegion(vaddr, local)); - local.WriteStr("Hello!"); + + DenaliRead read{ + .device_id = 0, + .lba = 0, + .size = 1, + }; + check(ZChannelSend(local.cap(), DENALI_READ, sizeof(DenaliRead), + reinterpret_cast(&read), 0, nullptr)); + + DenaliReadResponse resp; + uint64_t mem_cap, type, bytes, caps; + + check(ZChannelRecv(local.cap(), sizeof(resp), + reinterpret_cast(&resp), 1, &mem_cap, &type, + &bytes, &caps)); + + dbgln("Resp: %u", type); + + check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, mem_cap, &vaddr)); + uint32_t* mbr = reinterpret_cast(vaddr + 0x1FE); + dbgln("MBR: %x", *mbr); DumpPciEDevices();