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.
This commit is contained in:
Drew Galbraith 2023-06-08 02:36:59 -07:00
parent 47e3d11060
commit 30bb10207e
12 changed files with 264 additions and 44 deletions

View File

@ -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
)

View File

@ -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; \
} \
}

View File

@ -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

View File

@ -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}"
)

View File

@ -3,3 +3,4 @@
Current Processes;
- **yellowstone**: System Initialization
- **denali**: SATA ACHI Disk Driver

17
sys/denali/CMakeLists.txt Normal file
View File

@ -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}"
)

View File

@ -0,0 +1,149 @@
#include "ahci/ahci_driver.h"
#include <mammoth/debug.h>
#include <stdint.h>
#include <zcall.h>
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<uint64_t>(ahci_hba_) + 0x100 + (0x80 * port_index);
AhciPort* port = reinterpret_cast<AhciPort*>(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<PciDeviceHeader*>(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<AhciHba*>(vaddr);
return Z_OK;
}

View File

@ -0,0 +1,76 @@
#pragma once
#include <zerrors.h>
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();
};

8
sys/denali/denali.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <stdint.h>
#include "ahci/ahci_driver.h"
int main(uint64_t bootstrap_cap) {
AhciDriver driver;
return driver.Init();
}

View File

@ -1,28 +0,0 @@
#include <mammoth/channel.h>
#include <mammoth/debug.h>
#include <mammoth/thread.h>
#include <stdlib.h>
void thread_entry(void* a) {
dbgln("In thread");
dbgln(static_cast<const char*>(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;
}

View File

@ -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

View File

@ -123,7 +123,7 @@ void LoadInitProgram() {
uint64_t entry = LoadElfProgram(
*proc, reinterpret_cast<uint64_t>(init_prog.address), init_prog.size);
const limine_file& prog2 = GetInitProgram("/sys/test2");
const limine_file& prog2 = GetInitProgram("/sys/denali");
RefPtr<MemoryObject> prog2_vmmo = MakeRefCounted<MemoryObject>(prog2.size);
prog2_vmmo->CopyBytesToObject(reinterpret_cast<uint64_t>(prog2.address),
prog2.size);