colonel.exe 🤑, refactor all include directives, AHCI is now interrupt driven, upgrades to IDE, implemented I/O Request Packets, fix numerous keyboard issues, change all for (;;) and while (1) to while (true), DbgPrint guarded by spinlock, fix KeSignalEvent, major KernelMain refactor, added SystemInitThread because of new blocking I/O, replace memcpy manouvers with strncpy and strncat, add: run for ide, runa for ahci, rund for debug and ide, runad for debug and ahci.

This commit is contained in:
maksw committed 2026-05-03 19:35:48 +02:00
1 parent 7f4052f41c
commit 9fa2a7e0db
61 files changed
+1311 -456

No files matched your search

+109 -83
View File
@@ -1,19 +1,18 @@
// ide.c - PIO-mode IDE driver (legacy 28-bit LBA)
#include <io_driver.h>
#include <hal_api.h>
#include <ke_debug.h>
#include <stdint.h>
#include <string.h>
#include <intrin.h>
#include <io_driver.h>
#include <hal_api.h>
#include <ke_debug.h>
#include <ke_sched.h>
// Primary channel I/O ports.
#define IDE_DATA 0x1F0
#define IDE_ERR 0x1F1
#define IDE_SECCNT 0x1F2
#define IDE_LBA0 0x1F3
#define IDE_LBA1 0x1F4
#define IDE_LBA2 0x1F5
#define IDE_DRIVE 0x1F6 // 0xE0=master 0xF0=slave
#define IDE_DRIVE 0x1F6
#define IDE_STATUS 0x1F7
#define IDE_CMD 0x1F7
#define IDE_ALT 0x3F6
@@ -23,69 +22,112 @@
#define IDE_ERR_F 0x01
#define IDE_DRQ 0x08
#define CMD_READ 0x20
#define CMD_WRITE 0x30
#define CMD_IDENT 0xEC
// 48-bit LBA Commands
#define CMD_READ_EXT 0x24
#define CMD_WRITE_EXT 0x34
#define CMD_IDENT 0xEC
static const HAL_API* gHal;
static DISK_DRIVER gDrv;
static uint64_t gSectorCount = 0;
static bool gSupportsLba48 = false;
// ---------------------------------------------------------
// Polling Upgrades: Yield instead of blocking the CPU
// ---------------------------------------------------------
static void IdeWait(void) {
while (__inbyte(IDE_STATUS) & IDE_BUSY) _mm_pause();
while (__inbyte(IDE_STATUS) & IDE_BUSY) {
KeYield(); // <-- Let other threads run while the disk thinks!
}
}
static KSTATUS IdeWaitData(void) {
// Read the Alternate Status port 4 times to waste 400ns
for (int i = 0; i < 4; i++) {
__inbyte(IDE_ALT);
}
for (int i = 0; i < 4; i++) __inbyte(IDE_ALT);
// Wait until the drive is not busy AND data is requested (DRQ)
while (1) {
while (true) {
uint8_t st = __inbyte(IDE_STATUS);
if (st & IDE_ERR_F) return STATUS_DEVICE_ERROR;
if (!(st & IDE_BUSY) && (st & IDE_DRQ)) return STATUS_SUCCESS;
_mm_pause();
KeYield(); // <-- Be a good citizen
}
}
static KSTATUS IdeRead(uint64_t lba, uint32_t count, void* buf) {
// ---------------------------------------------------------
// 48-Bit LBA Read/Write
// ---------------------------------------------------------
static KSTATUS IdeRead(void *ctx, uint64_t lba, uint32_t count, void* buf) {
(void)ctx;
if (lba + count > gSectorCount) return STATUS_INVALID_PARAMETER;
uint16_t* p = (uint16_t *)buf;
// For simplicity, handle one sector at a time in this loop
for (uint32_t i = 0; i < count; i++, lba++) {
IdeWait(); // Wait for drive to be ready for commands
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, CMD_READ);
IdeWait();
if (gSupportsLba48) {
// LBA48 requires writing high bytes first, then low bytes
__outbyte(IDE_DRIVE, 0x40); // 0x40 = LBA mode, drive 0
__outbyte(IDE_SECCNT, 0); // Count High
__outbyte(IDE_LBA0, (lba >> 24) & 0xFF); // LBA 4
__outbyte(IDE_LBA1, (lba >> 32) & 0xFF); // LBA 5
__outbyte(IDE_LBA2, (lba >> 40) & 0xFF); // LBA 6
__outbyte(IDE_SECCNT, 1); // Count Low
__outbyte(IDE_LBA0, (uint8_t)lba); // LBA 1
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8)); // LBA 2
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));// LBA 3
__outbyte(IDE_CMD, CMD_READ_EXT);
} else {
// Fallback to 28-bit
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, 0x20); // CMD_READ (28-bit)
}
// Use the delay/DRQ wait
if (IdeWaitData() != STATUS_SUCCESS) return STATUS_DEVICE_ERROR;
for (int w = 0; w < 256; w++) *p++ = __inword(IDE_DATA);
}
return STATUS_SUCCESS;
}
static KSTATUS IdeWrite(uint64_t lba, uint32_t count, const void* buf) {
static KSTATUS IdeWrite(void *ctx, uint64_t lba, uint32_t count, const void* buf) {
(void)ctx;
if (lba + count > gSectorCount) return STATUS_INVALID_PARAMETER;
const uint16_t* p = (const uint16_t *)buf;
for (uint32_t i = 0; i < count; i++, lba++) {
IdeWait();
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, CMD_WRITE);
if (gSupportsLba48) {
__outbyte(IDE_DRIVE, 0x40);
__outbyte(IDE_SECCNT, 0);
__outbyte(IDE_LBA0, (lba >> 24) & 0xFF);
__outbyte(IDE_LBA1, (lba >> 32) & 0xFF);
__outbyte(IDE_LBA2, (lba >> 40) & 0xFF);
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, CMD_WRITE_EXT);
} else {
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, 0x30); // CMD_WRITE (28-bit)
}
IdeWait();
for (int w = 0; w < 256; w++) __outword(IDE_DATA, *p++);
__outbyte(IDE_ALT, 0); // flush cache
__outbyte(IDE_ALT, 0); // flush cache
if (IdeWaitData() != STATUS_SUCCESS) return STATUS_DEVICE_ERROR;
}
return STATUS_SUCCESS;
@@ -94,83 +136,67 @@ static KSTATUS IdeWrite(uint64_t lba, uint32_t count, const void* buf) {
KSTATUS DriverEntry(const HAL_API* hal) {
DbgPrint("IDE: Init\n");
gHal = hal;
uint8_t status;
int timeout;
// 1. Select Primary Master Drive (0xA0)
// Select Primary Master (Drive 0)
__outbyte(IDE_DRIVE, 0xA0);
// Waste 400ns to let the drive selection settle on the bus
for(int i=0; i<4; i++) __inbyte(IDE_ALT);
// 2. Zero out the LBA and Sector Count registers
__outbyte(IDE_SECCNT, 0);
__outbyte(IDE_LBA0, 0);
__outbyte(IDE_LBA1, 0);
__outbyte(IDE_LBA2, 0);
// 3. Send the IDENTIFY command
DbgPrint("IDE: Sending CMD_IDENT (0xEC)...\n");
__outbyte(IDE_CMD, CMD_IDENT);
// 4. Read status immediately. If it's 0, the drive doesn't exist at all.
status = __inbyte(IDE_STATUS);
// DbgPrint("IDE: Initial status after IDENTIFY: 0x%02X\n", status);
if (status == 0) {
DbgPrint("IDE ERROR: Drive does not exist (Status 0).\n");
if (__inbyte(IDE_STATUS) == 0) {
// QEMU usually falls in here because it uses AHCI by default,
// leaving the legacy IDE ports floating/unconnected.
DbgPrint("IDE ERROR: Drive does not exist on legacy port 0x1F0.\n");
return STATUS_NOT_FOUND;
}
// 5. Wait for BSY (Busy) to clear, WITH A TIMEOUT
timeout = 100000;
// Wait for BSY to clear, yielding to scheduler
int timeout = 10000;
while (__inbyte(IDE_STATUS) & IDE_BUSY) {
if (--timeout == 0) {
DbgPrint("IDE ERROR: Timeout waiting for BSY to clear!\n");
return STATUS_DEVICE_ERROR;
}
if (--timeout == 0) return STATUS_DEVICE_ERROR;
KeYield();
}
// 6. Check for ATAPI (CD-ROM) or SATA signatures.
// If these registers aren't 0 after BSY clears, it's NOT a standard ATA disk!
uint8_t lba1 = __inbyte(IDE_LBA1);
uint8_t lba2 = __inbyte(IDE_LBA2);
if (lba1 != 0 || lba2 != 0) {
DbgPrint("IDE ERROR: Not an ATA drive! Signatures: LBA1=0x%02X, LBA2=0x%02X\n", lba1, lba2);
// (ATAPI CD-ROMs usually show LBA1=0x14, LBA2=0xEB)
if (__inbyte(IDE_LBA1) != 0 || __inbyte(IDE_LBA2) != 0) {
DbgPrint("IDE ERROR: Not a standard ATA drive (Possibly ATAPI).\n");
return STATUS_NOT_SUPPORTED;
}
// 7. Wait for DRQ (Data Request) or ERR (Error)
timeout = 100000;
while (1) {
status = __inbyte(IDE_STATUS);
if (status & IDE_ERR_F) {
DbgPrint("IDE ERROR: Drive returned an error! Status: 0x%02X\n", status);
return STATUS_DEVICE_ERROR;
}
if (status & IDE_DRQ) {
break; // Data is ready!
}
if (--timeout == 0) {
DbgPrint("IDE ERROR: Timeout waiting for DRQ! Status: 0x%02X\n", status);
return STATUS_DEVICE_ERROR;
}
timeout = 10000;
while (true) {
uint8_t status = __inbyte(IDE_STATUS);
if (status & IDE_ERR_F) return STATUS_DEVICE_ERROR;
if (status & IDE_DRQ) break;
if (--timeout == 0) return STATUS_DEVICE_ERROR;
KeYield();
}
// 8. Success! Read the 256 words (512 bytes) of IDENTIFY data
// DbgPrint("IDE: DRQ set! Reading 256 words...\n");
uint16_t ident[256];
for (int i = 0; i < 256; i++) {
ident[i] = __inword(IDE_DATA);
}
// 9. Extract and print the sector count (Words 60 and 61 for 28-bit LBA)
gSectorCount = ((uint32_t)ident[61] << 16) | ident[60];
DbgPrint("IDE: SUCCESS: Disk found! Sector count: %u\n", (uint32_t)gSectorCount);
// Word 83 Bit 10 determines LBA48 support
gSupportsLba48 = (ident[83] & (1 << 10)) != 0;
if (gSupportsLba48) {
// Words 100-103 contain the 64-bit LBA sector count
gSectorCount = *(uint64_t*)&ident[100];
DbgPrint("IDE: LBA48 Disk found! Sectors: %llu\n", gSectorCount);
} else {
// Fallback to 28-bit
gSectorCount = ((uint32_t)ident[61] << 16) | ident[60];
DbgPrint("IDE: LBA28 Disk found! Sectors: %u\n", (uint32_t)gSectorCount);
}
if (gSectorCount == 0) return STATUS_NOT_FOUND;
// Register driver globally (from the previous fix!)
gDrv.Ctx = NULL;
gDrv.ReadSectors = IdeRead;
gDrv.WriteSectors = IdeWrite;
gDrv.SectorCount = gSectorCount;