summaryrefslogtreecommitdiffhomepage
path: root/dev/ZKAKit/HALKit
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-11-20 21:01:31 +0100
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-11-20 21:01:31 +0100
commit50439432a85976605dbb18e3cd2161f888d2e17d (patch)
tree12a30d88888f407e84634badef430d321cd1f4c6 /dev/ZKAKit/HALKit
parent745cc52b11190689a3f42b936978a5c03a410b9a (diff)
IMP: AHCI-DMA: driver improvements, does complete read now (although nothing returns).
ReadMe.md: Update git ssh link. HWTS: Refactor class. DriveMgr: Lots of improvements inside the API. CUSA: Refactor scheduler API too.
Diffstat (limited to 'dev/ZKAKit/HALKit')
-rw-r--r--dev/ZKAKit/HALKit/AMD64/HalKernelMain.cc12
-rw-r--r--dev/ZKAKit/HALKit/AMD64/Storage/AHCI-DMA.cc307
2 files changed, 145 insertions, 174 deletions
diff --git a/dev/ZKAKit/HALKit/AMD64/HalKernelMain.cc b/dev/ZKAKit/HALKit/AMD64/HalKernelMain.cc
index aa164eea..9ceefbc2 100644
--- a/dev/ZKAKit/HALKit/AMD64/HalKernelMain.cc
+++ b/dev/ZKAKit/HALKit/AMD64/HalKernelMain.cc
@@ -20,15 +20,8 @@ EXTERN_C Kernel::Char mp_user_switch_proc_stack_begin[];
EXTERN_C Kernel::MainKind __CTOR_LIST__[];
EXTERN_C Kernel::MainKind __DTOR_LIST__[];
-namespace Kernel
-{
- EXTERN ProcessID kProcessIDCounter;
-}
-
STATIC Kernel::Void hal_init_cxx_ctors()
{
- Kernel::kProcessIDCounter = 0UL;
-
for (Kernel::SizeT index = 0UL; __CTOR_LIST__[index] != __DTOR_LIST__[0]; ++index)
{
Kernel::MainKind constructor_cxx = (Kernel::MainKind)__CTOR_LIST__[index];
@@ -90,12 +83,15 @@ EXTERN_C Kernel::Void hal_real_init(Kernel::Void) noexcept
{
/* Initialize filesystem. */
Kernel::NeFileSystemMgr::Mount(new Kernel::NeFileSystemMgr());
+ Kernel::UserProcessHelper::InitScheduler();
const Kernel::Char process_name[] = "Kernel";
Kernel::rtl_create_process([]() -> void {
while (Yes)
- ;
+ {
+ kcout << "Scheduling...\r";
+ }
},
process_name);
diff --git a/dev/ZKAKit/HALKit/AMD64/Storage/AHCI-DMA.cc b/dev/ZKAKit/HALKit/AMD64/Storage/AHCI-DMA.cc
index 99e1b4c1..06ba1c6f 100644
--- a/dev/ZKAKit/HALKit/AMD64/Storage/AHCI-DMA.cc
+++ b/dev/ZKAKit/HALKit/AMD64/Storage/AHCI-DMA.cc
@@ -15,17 +15,29 @@
*
*/
+#include <Modules/ATA/ATA.h>
#include <Modules/AHCI/AHCI.h>
#include <KernelKit/PCI/Iterator.h>
#include <NewKit/Utils.h>
#include <KernelKit/LockDelegate.h>
#ifdef __AHCI__
+
+#define kAhciCmdTblBase mib_cast(1) // 4M
+
+#define HBA_PxCMD_ST 0x0001
+#define HBA_PxCMD_FRE 0x0010
+#define HBA_PxCMD_FR 0x4000
+#define HBA_PxCMD_CR 0x8000
+
#define kMaxAhciPoll (100000U)
#define kCmdOrCtrlCmd 1
#define kCmdOrCtrlCtrl 0
+#define kAhciSRBsy 0x80
+#define kAhciSRDrq 0x08
+
enum
{
kSATAProgIfAHCI = 0x01,
@@ -39,68 +51,8 @@ STATIC Kernel::Lba kCurrentDiskSectorCount = 0UL;
Kernel::Void drv_calculate_disk_geometry()
{
- // Slot is now used, OS uses slot 0, driver must not use slot 0.
-
- // Prepare command header.
-
- HbaCmdHeader* cmd_header = (HbaCmdHeader*)(Kernel::UIntPtr)kAhciPort->Clb;
-
- // Read operation/set entries count.
-
- Kernel::UInt16 identify_data[256] = {0};
- Kernel::UInt64 size = 512 - 1; // Adjust size for 512 bytes of data (Dbc should be 511)
-
- cmd_header->Cfl = sizeof(FisRegH2D) / sizeof(Kernel::UInt32);
- cmd_header->Prdtl = 1; // 1 PRDT entry
-
- // Prepare command table.
- HbaCmdTbl* cmd_tbl = (HbaCmdTbl*)(Kernel::UIntPtr)cmd_header->Ctba;
-
- // First PRD entry
- cmd_tbl->PrdtEntries[0].Dba = (Kernel::UInt32)(Kernel::UIntPtr)identify_data;
- cmd_tbl->PrdtEntries[0].Dbc = size; // Byte count (511 for 512 bytes of data)
- cmd_tbl->PrdtEntries[0].InterruptBit = 1; // Set interrupt flag
-
- // 5. Prepare the command FIS (Frame Information Structure)
- FisRegH2D* cmd_fis = (FisRegH2D*)(cmd_tbl->Cfis);
- cmd_fis->FisType = kFISTypeRegH2D;
- cmd_fis->CmdOrCtrl = kCmdOrCtrlCmd; // Command
- cmd_fis->Command = kAHCICmdIdentify;
-
- // 6. Issue the command by writing to the port's command issue register (CI)
- kAhciPort->Ci = 1; // Issue command slot 0
-
- // Polling loop for command completion
- while (kAhciPort->Ci)
- {
- // Check for errors in the Task File Data register (PxTFD)
- if (kAhciPort->Tfd & (1 << 0))
- { // Error bit
- kcout << "Error in task file, can't get disk geometry." << endl;
- Kernel::ke_stop(RUNTIME_CHECK_UNEXCPECTED);
- }
-
- // If the device is busy, wait
- if (kAhciPort->Tfd & (1 << 7))
- {
- kcout << "Device is busy, waiting..." << endl;
- continue;
- }
-
- // If command completes, clear the PxCI register
- if (kAhciPort->Is & (1 << 30))
- { // If an interrupt occurred (device ready)
- kcout << "Command completed successfully." << endl;
- break;
- }
- }
-
- // Retrieve the max LBA value
- kCurrentDiskSectorCount = *(Kernel::UIntPtr*)identify_data;
-
+ kCurrentDiskSectorCount = 0UL;
kcout << "Max LBA: " << Kernel::number(kCurrentDiskSectorCount) << endl;
-
- BREAK_POINT();
}
/// @brief Initializes an AHCI disk.
@@ -120,7 +72,7 @@ Kernel::Boolean drv_std_init(Kernel::UInt16& PortsImplemented)
if (kAhciDevice.Subclass() == kSATASubClass &&
kAhciDevice.ProgIf() == kSATAProgIfAHCI)
{
- kAhciDevice.EnableMmio(0x24); // Enable the memory index_byte/o for this ahci device.
+ kAhciDevice.EnableMmio(0x24); // Enable the memory index_byte/o for this ahci device.
kAhciDevice.BecomeBusMaster(0x24); // Become bus master for this ahci device, so that we can control it.
HbaMem* mem_ahci = (HbaMem*)kAhciDevice.Bar(0x24);
@@ -152,6 +104,65 @@ Kernel::Boolean drv_std_init(Kernel::UInt16& PortsImplemented)
kAhciPort = &mem_ahci->Ports[ahci_index];
+ kAhciPort->Cmd &= ~HBA_PxCMD_FRE;
+
+ // Clear FRE (bit4)
+ kAhciPort->Cmd &= ~HBA_PxCMD_ST;
+
+ // Wait until FR (bit14), CR (bit15) are cleared
+ while (YES)
+ {
+ if (kAhciPort->Cmd & HBA_PxCMD_CR)
+ continue;
+
+ if (kAhciPort->Cmd & HBA_PxCMD_FR)
+ continue;
+ break;
+ }
+
+ // when it's stopped.
+
+ // do in-between
+
+ kAhciPort->Clb = kAhciCmdTblBase + (ahci_index << 10);
+ kAhciPort->Clbu = 0;
+ rt_set_memory((void*)(kAhciPort->Clb), 0, 1024);
+
+ // FIS offset: 32K+256*ahci_index
+ // FIS entry size = 256 bytes per port
+ kAhciPort->Fb = kAhciCmdTblBase + (32 << 10) + (ahci_index << 8);
+ kAhciPort->Fbu = 0;
+ rt_set_memory((void*)(kAhciPort->Fb), 0, 256);
+
+ // Command table offset: 40K + 8K*ahci_index
+ // Command table size = 256*32 = 8K per port
+ HbaCmdHeader* cmdheader = (HbaCmdHeader*)(kAhciPort->Clb);
+
+ for (int i = 0; i < 32; i++)
+ {
+ cmdheader[i].Prdtl = 8; // 8 prdt entries per command table
+ // 256 bytes per command table, 64+16+48+16*8
+ // Command table offset: 40K + 8K*ahci_index + cmdheader_index*256
+ cmdheader[i].Ctba = kAhciCmdTblBase + (40 << 10) + (ahci_index << 13) + (i << 8);
+ cmdheader[i].Ctbau = 0;
+
+ rt_set_memory((void*)cmdheader[i].Ctba, 0, 256);
+ }
+
+ // when it's starting
+
+ // check for bits again, to start it again.
+ while (YES)
+ {
+ if (kAhciPort->Cmd & HBA_PxCMD_FR)
+ continue;
+
+ break;
+ }
+
+ kAhciPort->Cmd |= HBA_PxCMD_FRE;
+ kAhciPort->Cmd |= HBA_PxCMD_ST;
+
drv_calculate_disk_geometry();
break;
@@ -174,138 +185,102 @@ Kernel::Boolean drv_std_detected(Kernel::Void)
return kAhciDevice.DeviceId() != 0xFFFF;
}
-Kernel::Void drv_std_read(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_sz, Kernel::SizeT size_buffer)
+Kernel::Void drv_std_write(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_cnt, Kernel::SizeT size_buffer)
{
- // Slot is now used, OS uses slot 0, driver must not use slot 0.
+}
- // Prepare command header.
+Kernel::Void drv_std_read(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_cnt, Kernel::SizeT size_buffer)
+{
+ kAhciPort->Is = -1;
+ int port = 0;
+ Kernel::UInt32 slots = (kAhciPort->Sact | kAhciPort->Ci);
- HbaCmdHeader* cmd_header = (HbaCmdHeader*)(Kernel::UIntPtr)kAhciPort->Clb;
+ for (; port < slots; ++port)
+ {
+ if ((slots & 1) == 0)
+ break;
- // Read operation/set entries count.
+ slots >>= 1;
+ }
- cmd_header->Write = No;
- cmd_header->Prdtl = (Kernel::UInt16)((size_buffer - 1) >> 4) + 1; // PRDT entries count
+ HbaCmdHeader* cmd_hdr = (HbaCmdHeader*)(kAhciPort->Clb);
- // Prepare command table.
+ cmd_hdr += port;
+ cmd_hdr->Cfl = sizeof(FisRegH2D) / sizeof(Kernel::UInt32);
+ cmd_hdr->Write = NO;
+ cmd_hdr->Prdtl = (Kernel::UInt16)((sector_cnt - 1) >> 4) + 1;
- HbaCmdTbl* cmd_tbl = (HbaCmdTbl*)(Kernel::UIntPtr)cmd_header->Ctba;
- Kernel::rt_set_memory(cmd_tbl, 0, sizeof(HbaCmdTbl));
+ HbaCmdTbl* cmd_tbl = (HbaCmdTbl*)(cmd_hdr->Ctba);
+ Kernel::rt_set_memory(cmd_tbl, 0, (cmd_hdr->Prdtl - 1) * sizeof(HbaPrdtEntry));
- Kernel::UInt64 size = size * kAHCISectorSize;
- Kernel::Int64 index_byte = 0L;
+ int i = 0;
- cmd_tbl->PrdtEntries[index_byte].Dba = (Kernel::UInt32)(Kernel::UIntPtr)buffer;
- cmd_tbl->PrdtEntries[index_byte].Dbc = size; // 8KB buffer size
- cmd_tbl->PrdtEntries[index_byte].InterruptBit = 1; // Interrupt on completion
+ for (int i = 0; i < cmd_hdr->Prdtl - 1; i++)
+ {
+ cmd_tbl->PrdtEntries[i].Dba = (Kernel::UInt32)(Kernel::UInt64)buffer;
+ cmd_tbl->PrdtEntries[i].Dba = (Kernel::UInt32)((Kernel::UInt64)(buffer) >> 32);
+ cmd_tbl->PrdtEntries[i].Dbc = size_buffer - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
+ cmd_tbl->PrdtEntries[i].InterruptBit = 1;
+ }
- // Last PRDT entry
- cmd_tbl->PrdtEntries[index_byte].Dba = (Kernel::UInt32)(Kernel::UIntPtr)buffer;
- cmd_tbl->PrdtEntries[index_byte].Dbc = size - 1; // Byte count left
- cmd_tbl->PrdtEntries[index_byte].InterruptBit = 1;
+ cmd_tbl->PrdtEntries[i].Dba = (Kernel::UInt32)(Kernel::UInt64)buffer;
+ cmd_tbl->PrdtEntries[i].Dba = (Kernel::UInt32)((Kernel::UInt64)(buffer) >> 32);
+ cmd_tbl->PrdtEntries[i].Dbc = size_buffer - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
+ cmd_tbl->PrdtEntries[i].InterruptBit = 1;
- // 5. Prepare the command FIS (Frame Information Structure)
FisRegH2D* cmd_fis = (FisRegH2D*)(&cmd_tbl->Cfis);
- Kernel::rt_set_memory(cmd_fis, 0, sizeof(FisRegH2D));
cmd_fis->FisType = kFISTypeRegH2D;
- cmd_fis->CmdOrCtrl = kCmdOrCtrlCmd; // Command
+ cmd_fis->CmdOrCtrl = YES; // Command
cmd_fis->Command = kAHCICmdReadDmaEx;
- cmd_fis->Lba0 = (Kernel::UInt8)lba;
- cmd_fis->Lba1 = (Kernel::UInt8)(lba >> 8);
- cmd_fis->Lba2 = (Kernel::UInt8)(lba >> 16);
- cmd_fis->Device = 1 << 6; // LBA mode
+ cmd_fis->Lba0 = (Kernel::UInt8)(Kernel::UInt32)lba & 0xFF;
+ cmd_fis->Lba1 = (Kernel::UInt8)((Kernel::UInt32)lba >> 8);
+ cmd_fis->Lba2 = (Kernel::UInt8)((Kernel::UInt32)lba >> 16);
+ cmd_fis->Device = (1 << 6); // LBA mode
- cmd_fis->Lba3 = (Kernel::UInt8)(lba >> 24);
+ cmd_fis->Lba3 = (Kernel::UInt8)((Kernel::UInt32)lba >> 24);
cmd_fis->Lba4 = (Kernel::UInt8)(lba >> 32);
- cmd_fis->Lba5 = (Kernel::UInt8)(lba >> 40);
+ cmd_fis->Lba5 = (Kernel::UInt8)((lba >> 32) >> 8);
- cmd_fis->CountLow = size & 0xFF;
- cmd_fis->CountHigh = (size >> 8) & 0xFF;
+ cmd_fis->CountLow = sector_cnt & 0xFF;
+ cmd_fis->CountHigh = (sector_cnt >> 8) & 0xFF;
- // 6. Issue the command by writing to the port's command issue register (CI)
- kAhciPort->Ci = 1;
+ Kernel::UInt64 spin = 0UL;
- // 7. Wait for the command to complete (simple spinlock, no need for an object here)
- while (Yes)
+ // The below loop waits until the port is no longer busy before issuing a new command
+ while ((kAhciPort->Tfd & (kAhciSRBsy | kAhciSRDrq)) && spin < kMaxAhciPoll)
{
- if (!(kAhciPort->Ci & 1))
- {
- break; // Command has completed
- }
- else if (kAhciPort->Is & (1 << 30))
- {
- return; // Error in task file
- }
+ spin++;
+ }
+ if (spin == 1000000)
+ {
+ kcout << "Port is hung\r";
+ return;
}
-}
-
-Kernel::Void drv_std_write(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_sz, Kernel::SizeT size_buffer)
-{
- // Prepare command header.
-
- HbaCmdHeader* cmd_header = (HbaCmdHeader*)(Kernel::UIntPtr)kAhciPort->Clb;
-
- // Read operation/set entries count.
-
- cmd_header->Write = Yes;
- cmd_header->Prdtl = (Kernel::UInt16)((size_buffer - 1) >> 4) + 1; // PRDT entries count, put in low of prdt.
-
- // Prepare command table.
-
- HbaCmdTbl* cmd_tbl = (HbaCmdTbl*)(Kernel::UIntPtr)cmd_header->Ctba;
- Kernel::rt_set_memory(cmd_tbl, 0, sizeof(HbaCmdTbl));
-
- Kernel::UInt64 size = size * kAHCISectorSize;
- Kernel::Int64 index_byte = 0L;
-
- cmd_tbl->PrdtEntries[index_byte].Dba = (Kernel::UInt32)(Kernel::UIntPtr)buffer;
- cmd_tbl->PrdtEntries[index_byte].Dbc = size; // 8KB buffer size
- cmd_tbl->PrdtEntries[index_byte].InterruptBit = 1; // Interrupt on completion
-
- // Last PRDT entry
- cmd_tbl->PrdtEntries[index_byte].Dba = (Kernel::UInt32)(Kernel::UIntPtr)buffer;
- cmd_tbl->PrdtEntries[index_byte].Dbc = size - 1; // Byte count left
- cmd_tbl->PrdtEntries[index_byte].InterruptBit = 1;
-
- // 5. Prepare the command FIS (Frame Information Structure)
- FisRegH2D* cmd_fis = (FisRegH2D*)(&cmd_tbl->Cfis);
- Kernel::rt_set_memory(cmd_fis, 0, sizeof(FisRegH2D));
-
- cmd_fis->FisType = kFISTypeRegH2D;
- cmd_fis->CmdOrCtrl = kCmdOrCtrlCmd; // Command
- cmd_fis->Command = kAHCICmdReadDmaEx;
-
- cmd_fis->Lba0 = (Kernel::UInt8)lba;
- cmd_fis->Lba1 = (Kernel::UInt8)(lba >> 8);
- cmd_fis->Lba2 = (Kernel::UInt8)(lba >> 16);
- cmd_fis->Device = 1 << 6; // LBA mode
-
- cmd_fis->Lba3 = (Kernel::UInt8)(lba >> 24);
- cmd_fis->Lba4 = (Kernel::UInt8)(lba >> 32);
- cmd_fis->Lba5 = (Kernel::UInt8)(lba >> 40);
-
- cmd_fis->CountLow = size & 0xFF;
- cmd_fis->CountHigh = (size >> 8) & 0xFF;
- // 6. Issue the command by writing to the port's command issue register (CI)
- kAhciPort->Ci = 1;
+ kAhciPort->Ci = 1 << port; // Issue command
- // 7. Wait for the command to complete (simple spinlock, no need for an object here)
- while (Yes)
+ // Wait for completion
+ while (YES)
{
- if (!(kAhciPort->Ci & 1))
- {
- break; // Command has completed
- }
- else if (kAhciPort->Is & (1 << 30))
+ // In some longer duration reads, it may be helpful to spin on the DPS bit
+ // in the PxIS port field as well (1 << 5)
+ if ((kAhciPort->Ci & (1 << port)) == 0)
+ break;
+ if (kAhciPort->Is & (1 << 30)) // Task file error
{
- kcout << "Error in task file. (AHCI Drv)\r";
- Kernel::ke_stop(RUNTIME_CHECK_UNEXCPECTED);
- return; // Error in task file
+ kcout << ("Read disk error\r");
+ return;
}
}
+
+ // Check again for the last time.
+ if (kAhciPort->Is & (1 << 30)) // task file error status
+ {
+ kcout << ("Read disk error\r");
+ *buffer = 0;
+ }
}
/***
@@ -324,4 +299,4 @@ Kernel::SizeT drv_get_size()
return drv_get_sector_count() * kAHCISectorSize;
}
-#endif // __AHCI__
+#endif // ifdef __AHCI__ \ No newline at end of file