feat: disconnect Bluetooth devices, flush disks on shutdown/reboot, display progress in login.elf window

This commit is contained in:
2026-06-06 18:27:19 +02:00
parent b51ab42eb9
commit cee21738ee
24 changed files with 418 additions and 12 deletions
+34
View File
@@ -745,6 +745,9 @@ namespace Drivers::Storage::Ahci {
bdev.WriteSectors = [](void* ctx, uint64_t lba, uint32_t count, const void* buffer) -> bool {
return WriteSectors((int)(uintptr_t)ctx, lba, count, buffer);
};
bdev.Flush = [](void* ctx) -> bool {
return FlushCache((int)(uintptr_t)ctx);
};
bdev.Ctx = (void*)(uintptr_t)i;
bdev.SectorCount = g_ports[i].SectorCount;
bdev.SectorSize = g_ports[i].SectorSizeLog;
@@ -826,6 +829,37 @@ namespace Drivers::Storage::Ahci {
return ok;
}
bool FlushCache(int port) {
if (!g_initialized || port < 0 || port >= MAX_PORTS || !g_ports[port].Active) {
return false;
}
int slot = FindFreeSlot(port);
if (slot < 0) {
KernelLogStream(ERROR, "AHCI") << "FlushCache: no free command slot";
return false;
}
CommandHeader* hdr = &g_ports[port].CmdList[slot];
CommandTable* tbl = g_ports[port].CmdTables[slot];
// FLUSH CACHE EXT is a non-data command: no PRDT, no transfer direction.
memset(tbl, 0, sizeof(CommandTable) + sizeof(PrdtEntry) * MAX_PRDT_ENTRIES);
FisRegH2D* fis = (FisRegH2D*)tbl->CommandFis;
fis->FisType = (uint8_t)FisType::RegH2D;
fis->CmdCtl = 1; // Command
fis->Command = ATA_CMD_FLUSH_CACHE_EX;
fis->Device = (1 << 6); // LBA mode
hdr->CflPmpA = 5; // CFL = FIS length in dwords (FisRegH2D = 20 bytes)
hdr->Flags = 0; // read direction (no data either way)
hdr->PrdtLength = 0;
hdr->PrdByteCount = 0;
return IssueCommand(port, slot);
}
bool WriteSectors(int port, uint64_t lba, uint32_t count, const void* buffer) {
if (!g_initialized || port < 0 || port >= MAX_PORTS || !g_ports[port].Active) {
return false;
+8 -3
View File
@@ -167,9 +167,10 @@ namespace Drivers::Storage::Ahci {
// ATA commands
// =========================================================================
constexpr uint8_t ATA_CMD_IDENTIFY = 0xEC;
constexpr uint8_t ATA_CMD_READ_DMA_EX = 0x25; // READ DMA EXT (48-bit LBA)
constexpr uint8_t ATA_CMD_WRITE_DMA_EX = 0x35; // WRITE DMA EXT (48-bit LBA)
constexpr uint8_t ATA_CMD_IDENTIFY = 0xEC;
constexpr uint8_t ATA_CMD_READ_DMA_EX = 0x25; // READ DMA EXT (48-bit LBA)
constexpr uint8_t ATA_CMD_WRITE_DMA_EX = 0x35; // WRITE DMA EXT (48-bit LBA)
constexpr uint8_t ATA_CMD_FLUSH_CACHE_EX = 0xEA; // FLUSH CACHE EXT (48-bit)
// =========================================================================
// Constants
@@ -252,6 +253,10 @@ namespace Drivers::Storage::Ahci {
// Write sectors to a SATA device
bool WriteSectors(int port, uint64_t lba, uint32_t count, const void* buffer);
// Flush the device's write cache to media (FLUSH CACHE EXT). Returns true on
// success. Used during graceful shutdown to make pending writes durable.
bool FlushCache(int port);
// Get info about a specific port
const PortInfo* GetPortInfo(int port);
@@ -22,6 +22,10 @@ namespace Drivers::Storage {
struct BlockDevice {
bool (*ReadSectors)(void* ctx, uint64_t lba, uint32_t count, void* buffer);
bool (*WriteSectors)(void* ctx, uint64_t lba, uint32_t count, const void* buffer);
// Flush the device's volatile write cache to non-volatile media. Optional:
// a null pointer means the device has no write-back cache to flush (so a
// completed WriteSectors is already durable). Returns true on success.
bool (*Flush)(void* ctx);
void* Ctx;
uint64_t SectorCount;
uint16_t SectorSize;
+19
View File
@@ -665,6 +665,9 @@ namespace Drivers::Storage::Nvme {
bdev.WriteSectors = [](void* ctx, uint64_t lba, uint32_t count, const void* buffer) -> bool {
return WriteSectors((int)(uintptr_t)ctx, lba, count, buffer);
};
bdev.Flush = [](void* ctx) -> bool {
return Flush((int)(uintptr_t)ctx);
};
bdev.Ctx = (void*)(uintptr_t)i;
bdev.SectorCount = g_namespaces[i].SectorCount;
bdev.SectorSize = (uint16_t)g_namespaces[i].SectorSize;
@@ -770,6 +773,22 @@ namespace Drivers::Storage::Nvme {
return ok;
}
bool Flush(int ns) {
if (!g_initialized || ns < 0 || ns >= g_nsCount || !g_namespaces[ns].Active) {
return false;
}
// NVM Flush: commits the namespace's volatile write cache to media.
SqEntry cmd = {};
cmd.Opcode = IO_CMD_FLUSH;
cmd.Nsid = g_namespaces[ns].Nsid;
SubmitIoCommand(cmd);
CqEntry cqe;
return WaitIoCompletion(cqe);
}
bool WriteSectors(int ns, uint64_t lba, uint32_t count, const void* buffer) {
if (!g_initialized || ns < 0 || ns >= g_nsCount || !g_namespaces[ns].Active) {
return false;
+5
View File
@@ -120,6 +120,7 @@ namespace Drivers::Storage::Nvme {
// NVM I/O opcodes
// =========================================================================
constexpr uint8_t IO_CMD_FLUSH = 0x00;
constexpr uint8_t IO_CMD_READ = 0x02;
constexpr uint8_t IO_CMD_WRITE = 0x01;
@@ -187,6 +188,10 @@ namespace Drivers::Storage::Nvme {
// Write sectors to an NVMe namespace
bool WriteSectors(int ns, uint64_t lba, uint32_t count, const void* buffer);
// Flush the namespace's volatile write cache to media (NVM Flush command).
// Returns true on success. Used during graceful shutdown.
bool Flush(int ns);
// Get info about a specific namespace
const NamespaceInfo* GetNamespaceInfo(int ns);