From 30bb10207ec01b7514c1da3b8bb337cb40f872a8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 8 Jun 2023 02:36:59 -0700 Subject: [PATCH] Add the Denali disk driver. Begin enumerating information from the PCI structure and HBA AHCI structures. Currently the PCI structure address is hardcoded but it should be passed via a capability from the init process in the future. --- CMakeLists.txt | 2 +- lib/mammoth/include/mammoth/debug.h | 8 ++ scripts/build_image.sh | 2 +- sys/CMakeLists.txt | 13 +-- sys/README.md | 1 + sys/denali/CMakeLists.txt | 17 ++++ sys/denali/ahci/ahci_driver.cpp | 149 ++++++++++++++++++++++++++++ sys/denali/ahci/ahci_driver.h | 76 ++++++++++++++ sys/denali/denali.cpp | 8 ++ sys/test2.cpp | 28 ------ zion/boot/limine.cfg | 2 +- zion/loader/init_loader.cpp | 2 +- 12 files changed, 264 insertions(+), 44 deletions(-) create mode 100644 sys/denali/CMakeLists.txt create mode 100644 sys/denali/ahci/ahci_driver.cpp create mode 100644 sys/denali/ahci/ahci_driver.h create mode 100644 sys/denali/denali.cpp delete mode 100644 sys/test2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa209f0..509ab44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ set(QEMU_CMD qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio add_custom_command( OUTPUT disk.img COMMAND sudo sh ../scripts/build_image.sh disk.img - DEPENDS zion yellowstone test2 + DEPENDS zion yellowstone denali USES_TERMINAL ) diff --git a/lib/mammoth/include/mammoth/debug.h b/lib/mammoth/include/mammoth/debug.h index 800a05a..82ecf58 100644 --- a/lib/mammoth/include/mammoth/debug.h +++ b/lib/mammoth/include/mammoth/debug.h @@ -10,3 +10,11 @@ void dbgln(const char* fmt, ...); void check(uint64_t); void crash(const char*, z_err_t); + +#define RET_ERR(expr) \ + { \ + z_err_t _tmp_err = expr; \ + if (_tmp_err != Z_OK) { \ + return _tmp_err; \ + } \ + } diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 19c5bc4..6b3a45c 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -38,6 +38,6 @@ cp ../zion/boot/limine.cfg efi/ cp zion/zion efi/ mkdir -p efi/sys cp sys/yellowstone/yellowstone efi/sys/yellowstone -cp sys/test2 efi/sys/test2 +cp sys/denali/denali efi/sys/denali chown drew:drew $1 diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 4c16dab..b639c4b 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -1,16 +1,5 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_subdirectory(yellowstone) +add_subdirectory(denali) -add_executable(test2 - test2.cpp) - -target_link_libraries(test2 - cxx - mammoth_lib) - -set_target_properties(test2 - PROPERTIES - COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" - LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" - ) diff --git a/sys/README.md b/sys/README.md index 5988c48..8ffe8dc 100644 --- a/sys/README.md +++ b/sys/README.md @@ -3,3 +3,4 @@ Current Processes; - **yellowstone**: System Initialization +- **denali**: SATA ACHI Disk Driver diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt new file mode 100644 index 0000000..f4be0d5 --- /dev/null +++ b/sys/denali/CMakeLists.txt @@ -0,0 +1,17 @@ +add_executable(denali + ahci/ahci_driver.cpp + denali.cpp) + + +target_include_directories(denali + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(denali + cxx + mammoth_lib + ) + +set_target_properties(denali PROPERTIES + COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" + LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" + ) diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_driver.cpp new file mode 100644 index 0000000..e6e671e --- /dev/null +++ b/sys/denali/ahci/ahci_driver.cpp @@ -0,0 +1,149 @@ +#include "ahci/ahci_driver.h" + +#include +#include +#include + +namespace { + +const uint64_t kSataPciPhys = 0xB00FA000; +const uint64_t kPciSize = 0x1000; + +} // namespace + +z_err_t AhciDriver::Init() { + RET_ERR(LoadPciDeviceHeader()); + dbgln("ABAR: %x", pci_device_header_->abar); + RET_ERR(LoadHbaRegisters()); + dbgln("Version: %x", ahci_hba_->version); + DumpCapabilities(); + DumpPorts(); + return Z_OK; +} + +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); + if (caps & 0x20) { + dbgln("External SATA"); + } + if (caps & 0x40) { + dbgln("Enclosure Management"); + } + if (caps & 0x80) { + dbgln("Command Completion Coalescing"); + } + if (caps & 0x2000) { + dbgln("Partial State Capable"); + } + if (caps & 0x4000) { + dbgln("Slumber state capable"); + } + if (caps & 0x8000) { + dbgln("PIO Multiple DRQ Block"); + } + if (caps & 0x1'0000) { + dbgln("FIS-Based Switching"); + } + if (caps & 0x2'0000) { + dbgln("Port Multiplier"); + } + if (caps & 0x4'0000) { + dbgln("AHCI mode only"); + } + dbgln("Speed support: %u", (caps & 0xF0'0000) >> 20); + if (caps & 0x100'0000) { + dbgln("Command list override"); + } + if (caps & 0x200'0000) { + dbgln("Activity LED"); + } + if (caps & 0x400'0000) { + dbgln("Aggresive link power management"); + } + if (caps & 0x800'0000) { + dbgln("Staggered spin up"); + } + if (caps & 0x1000'0000) { + dbgln("Mechanical Switch Presence"); + } + if (caps & 0x2000'0000) { + dbgln("SNotification Register"); + } + if (caps & 0x4000'0000) { + dbgln("Native Command Queueing"); + } + if (caps & 0x8000'0000) { + dbgln("64bit Addressing"); + } + + // Secondary. + caps = ahci_hba_->capabilities_ext; + if (caps & 0x1) { + dbgln("BIOS/OS handoff"); + } + if (caps & 0x2) { + dbgln("NVMHCI Present"); + } + if (caps & 0x4) { + dbgln("Auto partial to slumber tranisitions"); + } + if (caps & 0x8) { + dbgln("Device sleep"); + } + if (caps & 0x10) { + dbgln("Aggressive device sleep management"); + } +} + +void AhciDriver::DumpPorts() { + dbgln("Ports implemented %x", ahci_hba_->port_implemented); + + uint64_t port_index = 0; + uint32_t ports_implemented = ahci_hba_->port_implemented; + while (ports_implemented) { + if (!(ports_implemented & 0x1)) { + ports_implemented >>= 1; + port_index++; + continue; + } + uint64_t port_addr = + reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * port_index); + AhciPort* port = reinterpret_cast(port_addr); + + dbgln(""); + dbgln("Port %u:", port_index); + dbgln("Comlist: %lx", port->command_list_base); + dbgln("FIS: %lx", port->fis_base); + dbgln("Command: %x", port->command); + dbgln("Signature: %x", port->signature); + dbgln("SATA status: %x", port->sata_status); + + ports_implemented >>= 1; + port_index++; + } +} + +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); + return Z_OK; +} + +z_err_t AhciDriver::LoadHbaRegisters() { + uint64_t vmmo_cap; + RET_ERR( + ZMemoryObjectCreatePhysical(pci_device_header_->abar, 0x1100, &vmmo_cap)); + + uint64_t vaddr; + RET_ERR(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap, &vaddr)); + ahci_hba_ = reinterpret_cast(vaddr); + return Z_OK; +} diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_driver.h new file mode 100644 index 0000000..a15f90b --- /dev/null +++ b/sys/denali/ahci/ahci_driver.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +struct PciDeviceHeader { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command_reg; + uint16_t status_reg; + uint8_t revision; + uint8_t prog_interface; + uint8_t subclass; + uint8_t class_code; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t bars[5]; + uint32_t abar; + uint32_t subsystem_id; + uint32_t expansion_rom; + uint8_t cap_ptr; + uint8_t reserved[7]; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint8_t min_grant; + uint8_t max_latency; +} __attribute__((packed)); + +struct AhciHba { + uint32_t capabilities; + uint32_t global_host_control; + uint32_t interrupt_status; + uint32_t port_implemented; + uint32_t version; + uint32_t ccc_ctl; // 0x14, Command completion coalescing control + uint32_t ccc_pts; // 0x18, Command completion coalescing ports + uint32_t em_loc; // 0x1C, Enclosure management location + uint32_t em_ctl; // 0x20, Enclosure management control + uint32_t capabilities_ext; + uint32_t bohc; // 0x28, BIOS/OS handoff control and status +}; + +struct AhciPort { + uint64_t command_list_base; + uint64_t fis_base; + uint32_t interrupt_status; + uint32_t interrupt_enable; + uint32_t command; + uint32_t reserved; + uint32_t task_file_data; + uint32_t signature; + uint32_t sata_status; + uint32_t sata_control; + uint32_t sata_error; + uint32_t sata_active; + uint32_t command_issue; + uint32_t sata_notification; + uint32_t fis_based_switching_ctl; + uint32_t device_sleep; +}; + +class AhciDriver { + public: + z_err_t Init(); + + void DumpCapabilities(); + void DumpPorts(); + + private: + PciDeviceHeader* pci_device_header_ = nullptr; + AhciHba* ahci_hba_ = nullptr; + + z_err_t LoadPciDeviceHeader(); + z_err_t LoadHbaRegisters(); +}; diff --git a/sys/denali/denali.cpp b/sys/denali/denali.cpp new file mode 100644 index 0000000..2247b5a --- /dev/null +++ b/sys/denali/denali.cpp @@ -0,0 +1,8 @@ +#include + +#include "ahci/ahci_driver.h" + +int main(uint64_t bootstrap_cap) { + AhciDriver driver; + return driver.Init(); +} diff --git a/sys/test2.cpp b/sys/test2.cpp deleted file mode 100644 index b711ce3..0000000 --- a/sys/test2.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include -#include - -void thread_entry(void* a) { - dbgln("In thread"); - dbgln(static_cast(a)); -} - -int main(uint64_t bootstrap_cap) { - dbgln("Main thread"); - - const char* a = "a"; - const char* b = "bee"; - const char* c = "cee"; - const char* d = "dee"; - Thread t1(thread_entry, a); - Thread t2(thread_entry, b); - - uint64_t size = 10; - char* buff = new char[size]; - Channel c1; - c1.adopt_cap(bootstrap_cap); - check(c1.ReadStr(buff, &size)); - dbgln(buff); - return 0; -} diff --git a/zion/boot/limine.cfg b/zion/boot/limine.cfg index 6634ce4..64d2f51 100644 --- a/zion/boot/limine.cfg +++ b/zion/boot/limine.cfg @@ -7,4 +7,4 @@ TIMEOUT=0 KERNEL_PATH=boot:///zion MODULE_PATH=boot:///sys/yellowstone - MODULE_PATH=boot:///sys/test2 + MODULE_PATH=boot:///sys/denali diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index 99a28ba..e85e958 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -123,7 +123,7 @@ void LoadInitProgram() { uint64_t entry = LoadElfProgram( *proc, reinterpret_cast(init_prog.address), init_prog.size); - const limine_file& prog2 = GetInitProgram("/sys/test2"); + const limine_file& prog2 = GetInitProgram("/sys/denali"); RefPtr prog2_vmmo = MakeRefCounted(prog2.size); prog2_vmmo->CopyBytesToObject(reinterpret_cast(prog2.address), prog2.size);