diff --git a/CMakeLists.txt b/CMakeLists.txt index 38d1c29..267714d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,8 @@ add_custom_target(run -parallel file:printer.out -drive file=VirtioDisk.img,format=raw,id=virtio_disk,if=none -device virtio-blk-pci,drive=virtio_disk,disable-legacy=on + -drive file=NVMeDisk.img,format=raw,id=nvme_disk,if=none + -device nvme,drive=nvme_disk,serial=nvme001 DEPENDS iso img extra-img ) @@ -242,7 +244,9 @@ add_custom_target(extra-img COMMAND ${QEMU_IMG} create -f raw VirtioDisk.img 128M COMMAND ${MKFS_FAT} -F 16 VirtioDisk.img COMMAND ${QEMU_IMG} create -f raw SataDisk.img 128M - COMMAND ${MKFS_NTFS} -F SataDisk.img + COMMAND ${MKFS_EXT2} -F SataDisk.img + COMMAND ${QEMU_IMG} create -f raw NVMeDisk.img 256M + COMMAND ${MKFS_EXT2} -F NVMeDisk.img COMMENT "Creating extra disk images" ) diff --git a/README.md b/README.md index 44f8a64..1fe642d 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,10 @@ ninja run - [x] List - NTFS - [x] Read - - [ ] Write - - [ ] Create - - [ ] Delete - - [ ] List + - [x] Write + - [x] Create + - [x] Delete + - [x] List - VFRFS (VoidFrame RAMFS) - [x] Read - [x] Write @@ -185,4 +185,5 @@ ninja run - Storage - [x] PATA (IDE) - [x] VirtIO Block - - [x] AHCI \ No newline at end of file + - [x] AHCI + - [x] NVMe \ No newline at end of file diff --git a/cmake/features.cmake b/cmake/features.cmake index 06f250b..a1da011 100644 --- a/cmake/features.cmake +++ b/cmake/features.cmake @@ -11,6 +11,7 @@ add_compile_definitions( VF_CONFIG_ENABLE_IDE VF_CONFIG_ENABLE_VFCOMPOSITOR VF_CONFIG_ENABLE_AHCI + VF_CONFIG_ENABLE_NVME VF_CONFIG_ENABLE_GENERIC_SOUND VF_CONFIG_RTC_CENTURY VF_CONFIG_LOAD_MB_MODULES diff --git a/cmake/source.cmake b/cmake/source.cmake index 6cc7b2c..f606e2a 100644 --- a/cmake/source.cmake +++ b/cmake/source.cmake @@ -88,6 +88,7 @@ set(DRIVER_SOURCES drivers/sound/SB16.c drivers/sound/Generic.c drivers/storage/AHCI.c + drivers/storage/NVMe.c drivers/LPT/LPT.c drivers/virtio/VirtioBlk.c drivers/vmware/SVGAII.c diff --git a/drivers/Vesa.c b/drivers/Vesa.c index 00b602d..e42d1b4 100644 --- a/drivers/Vesa.c +++ b/drivers/Vesa.c @@ -3,6 +3,7 @@ #include "Font.h" #include "Multiboot2.h" #include "Serial.h" +#include "math.h" #include "stdint.h" #include "stdlib.h" #include "x64.h" @@ -182,8 +183,8 @@ void VBEDrawRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32 void VBEDrawLine(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color) { if (!vbe_initialized) return; - int dx = ABSi((int)x1 - (int)x0); - int dy = ABSi((int)y1 - (int)y0); + int dx = abs((int)x1 - (int)x0); + int dy = abs((int)y1 - (int)y0); int sx = (x0 < x1) ? 1 : -1; int sy = (y0 < y1) ? 1 : -1; int err = dx - dy; diff --git a/drivers/storage/NVMe.c b/drivers/storage/NVMe.c new file mode 100644 index 0000000..39db112 --- /dev/null +++ b/drivers/storage/NVMe.c @@ -0,0 +1,382 @@ +#include "NVMe.h" +#include "Console.h" +#include "TSC.h" +#include "KernelHeap.h" +#include "MemOps.h" +#include "VMem.h" +#include "BlockDevice.h" +#include "Format.h" +#include "PCI/PCI.h" + +static NVMeController g_nvme_controller = {0}; + +// Forward declarations +static int NVMe_ReadBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer); +static int NVMe_WriteBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer); + +static uint32_t NVMe_ReadReg32(uint32_t offset) { + return *(volatile uint32_t*)(g_nvme_controller.mmio_base + offset); +} + +static void NVMe_WriteReg32(uint32_t offset, uint32_t value) { + *(volatile uint32_t*)(g_nvme_controller.mmio_base + offset) = value; +} + +static uint64_t NVMe_ReadReg64(uint32_t offset) { + return *(volatile uint64_t*)(g_nvme_controller.mmio_base + offset); +} + +static void NVMe_WriteReg64(uint32_t offset, uint64_t value) { + *(volatile uint64_t*)(g_nvme_controller.mmio_base + offset) = value; +} + +static int NVMe_WaitReady(int ready) { + int timeout = 5000; + while (timeout-- > 0) { + uint32_t csts = NVMe_ReadReg32(NVME_CSTS); + if (ready && (csts & NVME_CSTS_RDY)) return 0; + if (!ready && !(csts & NVME_CSTS_RDY)) return 0; + delay_us(1000); + } + return -1; +} + +static int NVMe_SubmitAdminCommand(NVMeSubmissionEntry* cmd) { + NVMeController* ctrl = &g_nvme_controller; + + // Copy command to submission queue + FastMemcpy(&ctrl->admin_sq[ctrl->admin_sq_tail], cmd, sizeof(NVMeSubmissionEntry)); + + // Update tail pointer + ctrl->admin_sq_tail = (ctrl->admin_sq_tail + 1) % NVME_ADMIN_QUEUE_SIZE; + + // Ring doorbell for Admin SQ (QID 0) + uint32_t db_shift = 2 + ctrl->dstrd; + uint32_t asq_db_off = 0x1000 + ((0 * 2 + 0) << db_shift); + NVMe_WriteReg32(asq_db_off, ctrl->admin_sq_tail); // Admin SQ doorbell + + // Wait for completion + int timeout = 5000; + while (timeout-- > 0) { + NVMeCompletionEntry* cqe = &ctrl->admin_cq[ctrl->admin_cq_head]; + uint16_t status = cqe->status; + + if ((status & 1) == ctrl->admin_cq_phase) { + // Command completed + ctrl->admin_cq_head = (ctrl->admin_cq_head + 1) % NVME_ADMIN_QUEUE_SIZE; + if (ctrl->admin_cq_head == 0) { + ctrl->admin_cq_phase = !ctrl->admin_cq_phase; + } + + // Ring completion doorbell for Admin CQ (QID 0) + uint32_t acq_db_off = 0x1000 + ((0 * 2 + 1) << db_shift); + NVMe_WriteReg32(acq_db_off, ctrl->admin_cq_head); // Admin CQ doorbell + + return (status >> 1) & 0x7FF; // Return status code + } + delay_us(100); + } + + return -1; // Timeout +} + +static int NVMe_SubmitIOCommand(NVMeSubmissionEntry* cmd) { + NVMeController* ctrl = &g_nvme_controller; + + // Copy command to I/O submission queue + FastMemcpy(&ctrl->io_sq[ctrl->io_sq_tail], cmd, sizeof(NVMeSubmissionEntry)); + + // Update tail pointer + ctrl->io_sq_tail = (ctrl->io_sq_tail + 1) % NVME_IO_QUEUE_SIZE; + + // Ring doorbell (I/O queue 1) + uint32_t db_shift = 2 + ctrl->dstrd; + uint32_t iosq_db_off = 0x1000 + ((1 * 2 + 0) << db_shift); + NVMe_WriteReg32(iosq_db_off, ctrl->io_sq_tail); // I/O SQ doorbell + + // Wait for completion + int timeout = 5000; + while (timeout-- > 0) { + NVMeCompletionEntry* cqe = &ctrl->io_cq[ctrl->io_cq_head]; + uint16_t status = cqe->status; + + if ((status & 1) == ctrl->io_cq_phase) { + // Command completed + ctrl->io_cq_head = (ctrl->io_cq_head + 1) % NVME_IO_QUEUE_SIZE; + if (ctrl->io_cq_head == 0) { + ctrl->io_cq_phase = !ctrl->io_cq_phase; + } + + // Ring completion doorbell (I/O queue 1) + uint32_t iocq_db_off = 0x1000 + ((1 * 2 + 1) << db_shift); + NVMe_WriteReg32(iocq_db_off, ctrl->io_cq_head); // I/O CQ doorbell + + return (status >> 1) & 0x7FF; // Return status code + } + delay_us(50); + } + + return -1; // Timeout +} + +static int NVMe_CreateIOQueues(void) { + NVMeController* ctrl = &g_nvme_controller; + + // Allocate I/O queues + ctrl->io_sq = (NVMeSubmissionEntry*)VMemAlloc(NVME_IO_QUEUE_SIZE * sizeof(NVMeSubmissionEntry)); + ctrl->io_cq = (NVMeCompletionEntry*)VMemAlloc(NVME_IO_QUEUE_SIZE * sizeof(NVMeCompletionEntry)); + + if (!ctrl->io_sq || !ctrl->io_cq) { + PrintKernel("NVMe: Failed to allocate I/O queues\n"); + return -1; + } + + FastMemset(ctrl->io_sq, 0, NVME_IO_QUEUE_SIZE * sizeof(NVMeSubmissionEntry)); + FastMemset(ctrl->io_cq, 0, NVME_IO_QUEUE_SIZE * sizeof(NVMeCompletionEntry)); + + ctrl->io_sq_phys = VMemGetPhysAddr((uint64_t)ctrl->io_sq); + ctrl->io_cq_phys = VMemGetPhysAddr((uint64_t)ctrl->io_cq); + ctrl->io_sq_tail = 0; + ctrl->io_cq_head = 0; + ctrl->io_cq_phase = 1; + + // Create I/O Completion Queue + NVMeSubmissionEntry cmd = {0}; + cmd.cdw0 = 0x05 | ((uint32_t)(++ctrl->next_cid) << 16); // CREATE_IO_CQ opcode + cmd.prp1 = ctrl->io_cq_phys; + cmd.cdw10 = ((NVME_IO_QUEUE_SIZE - 1) << 16) | 1; // Queue size and ID + cmd.cdw11 = 1; // Physically contiguous + + if (NVMe_SubmitAdminCommand(&cmd) != 0) { + PrintKernel("NVMe: Failed to create I/O completion queue\n"); + return -1; + } + + // Create I/O Submission Queue + FastMemset(&cmd, 0, sizeof(cmd)); + cmd.cdw0 = 0x01 | ((uint32_t)(++ctrl->next_cid) << 16); // CREATE_IO_SQ opcode + cmd.prp1 = ctrl->io_sq_phys; + cmd.cdw10 = ((NVME_IO_QUEUE_SIZE - 1) << 16) | 1; // Queue size and ID + cmd.cdw11 = (1 << 16) | 1; // CQ ID and physically contiguous + + if (NVMe_SubmitAdminCommand(&cmd) != 0) { + PrintKernel("NVMe: Failed to create I/O submission queue\n"); + return -1; + } + + return 0; +} + +static uint64_t NVMe_GetNamespaceSize(void) { + // Allocate buffer for identify data + uint8_t* identify_data = (uint8_t*)KernelMemoryAlloc(4096); + if (!identify_data) return 0; + + FastMemset(identify_data, 0, 4096); + uint64_t identify_phys = VMemGetPhysAddr((uint64_t)identify_data); + + // Send IDENTIFY command for namespace 1 + NVMeSubmissionEntry cmd = {0}; + cmd.cdw0 = NVME_ADMIN_IDENTIFY | ((uint32_t)(++g_nvme_controller.next_cid) << 16); + cmd.nsid = 1; // Namespace 1 + cmd.prp1 = identify_phys; + cmd.cdw10 = 0; // Identify namespace + + int result = NVMe_SubmitAdminCommand(&cmd); + if (result != 0) { + KernelFree(identify_data); + return 0x1000000; // Fallback size + } + + // Get namespace size from identify data (bytes 0-7) + uint64_t nsze = *(uint64_t*)identify_data; + + KernelFree(identify_data); + + return nsze ? nsze : 0x1000000; // Return size or fallback +} + +int NVMe_ReadSectors(uint64_t lba, uint16_t count, void* buffer) { + if (!g_nvme_controller.initialized) return -1; + + uint64_t buffer_phys = VMemGetPhysAddr((uint64_t)buffer); + + NVMeSubmissionEntry cmd = {0}; + cmd.cdw0 = NVME_CMD_READ | ((uint32_t)(++g_nvme_controller.next_cid) << 16); + cmd.nsid = 1; // Namespace 1 + cmd.prp1 = buffer_phys; + cmd.cdw10 = lba & 0xFFFFFFFF; + cmd.cdw11 = (lba >> 32) & 0xFFFFFFFF; + cmd.cdw12 = (count - 1); // 0-based count + + return NVMe_SubmitIOCommand(&cmd); +} + +int NVMe_WriteSectors(uint64_t lba, uint16_t count, const void* buffer) { + if (!g_nvme_controller.initialized) return -1; + + uint64_t buffer_phys = VMemGetPhysAddr((uint64_t)buffer); + + NVMeSubmissionEntry cmd = {0}; + cmd.cdw0 = NVME_CMD_WRITE | ((uint32_t)(++g_nvme_controller.next_cid) << 16); + cmd.nsid = 1; // Namespace 1 + cmd.prp1 = buffer_phys; + cmd.cdw10 = lba & 0xFFFFFFFF; + cmd.cdw11 = (lba >> 32) & 0xFFFFFFFF; + cmd.cdw12 = (count - 1); // 0-based count + + return NVMe_SubmitIOCommand(&cmd); +} + +static int NVMe_ReadBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer) { + (void)device; + return NVMe_ReadSectors(start_lba, count, buffer); +} + +static int NVMe_WriteBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer) { + (void)device; + return NVMe_WriteSectors(start_lba, count, buffer); +} + +int NVMe_Init(void) { + PrintKernel("NVMe: Initializing NVMe driver...\n"); + + // Find NVMe controller + PciDevice pci_dev; + if (PciFindByClass(NVME_CLASS_CODE, NVME_SUBCLASS, NVME_PROG_IF, &pci_dev) != 0) { + PrintKernel("NVMe: No NVMe controller found\n"); + return -1; + } + + g_nvme_controller.pci_device = pci_dev; + + // Enable PCI device + uint16_t cmd = PciReadConfig16(pci_dev.bus, pci_dev.device, pci_dev.function, PCI_COMMAND_REG); + cmd |= PCI_CMD_MEM_SPACE_EN | PCI_CMD_BUS_MASTER_EN; + PciWriteConfig16(pci_dev.bus, pci_dev.device, pci_dev.function, PCI_COMMAND_REG, cmd); + + // Map MMIO (NVMe typically uses a 64-bit BAR at BAR0/1) + uint32_t bar0_val = PciConfigReadDWord(pci_dev.bus, pci_dev.device, pci_dev.function, PCI_BAR0_REG); + uint64_t mmio_phys = 0; + bool is_mem_bar = ((bar0_val & 0x1) == 0); // bit0==0 => memory BAR + bool is_64bit_bar = ((bar0_val & 0x06) == 0x04); + if (is_mem_bar) { + if (is_64bit_bar) { + uint32_t bar1_val = PciConfigReadDWord(pci_dev.bus, pci_dev.device, pci_dev.function, PCI_BAR0_REG + 4); + mmio_phys = ((uint64_t)bar1_val << 32) | (uint64_t)(bar0_val & ~0xFULL); + } else { + mmio_phys = (uint64_t)(bar0_val & ~0xFULL); + } + } + if (mmio_phys == 0) { + PrintKernel("NVMe: Invalid MMIO base address\n"); + return -1; + } + + // Align physical address and size to page boundaries + uint64_t mmio_phys_aligned = mmio_phys & ~0xFFFULL; + uint64_t mmio_offset = mmio_phys - mmio_phys_aligned; + g_nvme_controller.mmio_size = GetPCIMMIOSize(&pci_dev, bar0_val); + uint64_t mmio_size_aligned = ((g_nvme_controller.mmio_size + mmio_offset + 0xFFFULL) & ~0xFFFULL); + + // Allocate virtual space + volatile uint8_t* mmio_base_raw = (volatile uint8_t*)VMemAlloc(mmio_size_aligned); + if (!mmio_base_raw) { + PrintKernel("NVMe: Failed to allocate virtual space\n"); + return -1; + } + + // Unmap RAM pages + if (VMemUnmap((uint64_t)mmio_base_raw, mmio_size_aligned) != VMEM_SUCCESS) { + PrintKernel("NVMe: Failed to unmap RAM pages\n"); + VMemFree((void*)mmio_base_raw, mmio_size_aligned); + return -1; + } + + // Map MMIO + uint64_t map_flags = PAGE_WRITABLE | PAGE_NOCACHE; + if (VMemMapMMIO((uint64_t)mmio_base_raw, mmio_phys_aligned, mmio_size_aligned, map_flags) != VMEM_SUCCESS) { + PrintKernel("NVMe: Failed to map MMIO\n"); + return -1; + } + + // Adjust base pointer to account for offset + g_nvme_controller.mmio_base = mmio_base_raw + mmio_offset; + g_nvme_controller.mmio_size = mmio_size_aligned; + + __asm__ volatile("mfence" ::: "memory"); + + // Read capabilities (for doorbell stride) + uint64_t cap = NVMe_ReadReg64(NVME_CAP); + g_nvme_controller.dstrd = (uint8_t)((cap >> 32) & 0xF); + + // Reset controller + NVMe_WriteReg32(NVME_CC, 0); + if (NVMe_WaitReady(0) != 0) { + PrintKernel("NVMe: Controller reset timeout\n"); + return -1; + } + + // Allocate admin queues + g_nvme_controller.admin_sq = (NVMeSubmissionEntry*)VMemAlloc(NVME_ADMIN_QUEUE_SIZE * sizeof(NVMeSubmissionEntry)); + g_nvme_controller.admin_cq = (NVMeCompletionEntry*)VMemAlloc(NVME_ADMIN_QUEUE_SIZE * sizeof(NVMeCompletionEntry)); + + if (!g_nvme_controller.admin_sq || !g_nvme_controller.admin_cq) { + PrintKernel("NVMe: Failed to allocate admin queues\n"); + return -1; + } + + FastMemset(g_nvme_controller.admin_sq, 0, NVME_ADMIN_QUEUE_SIZE * sizeof(NVMeSubmissionEntry)); + FastMemset(g_nvme_controller.admin_cq, 0, NVME_ADMIN_QUEUE_SIZE * sizeof(NVMeCompletionEntry)); + + g_nvme_controller.admin_sq_phys = VMemGetPhysAddr((uint64_t)g_nvme_controller.admin_sq); + g_nvme_controller.admin_cq_phys = VMemGetPhysAddr((uint64_t)g_nvme_controller.admin_cq); + g_nvme_controller.admin_sq_tail = 0; + g_nvme_controller.admin_cq_head = 0; + g_nvme_controller.admin_cq_phase = 1; + g_nvme_controller.next_cid = 0; + + // Configure admin queues + NVMe_WriteReg32(NVME_AQA, ((NVME_ADMIN_QUEUE_SIZE - 1) << 16) | (NVME_ADMIN_QUEUE_SIZE - 1)); + NVMe_WriteReg64(NVME_ASQ, g_nvme_controller.admin_sq_phys); + NVMe_WriteReg64(NVME_ACQ, g_nvme_controller.admin_cq_phys); + + // Enable controller + uint32_t cc = NVME_CC_EN | NVME_CC_CSS_NVM | NVME_CC_MPS_4K | NVME_CC_AMS_RR | NVME_CC_SHN_NONE | NVME_CC_IOSQES_64 | NVME_CC_IOCQES_16; + NVMe_WriteReg32(NVME_CC, cc); + + if (NVMe_WaitReady(1) != 0) { + PrintKernel("NVMe: Controller enable timeout\n"); + return -1; + } + + // Create I/O queues + if (NVMe_CreateIOQueues() != 0) { + PrintKernel("NVMe: Failed to create I/O queues\n"); + return -1; + } + + // Get namespace size + g_nvme_controller.namespace_size = NVMe_GetNamespaceSize(); + g_nvme_controller.initialized = 1; + + // Register block device + BlockDevice* nvme_device = BlockDeviceRegister( + DEVICE_TYPE_NVME, + 512, // Block size + g_nvme_controller.namespace_size, + "nvme0", + &g_nvme_controller, + NVMe_ReadBlocksWrapper, + NVMe_WriteBlocksWrapper + ); + + if (nvme_device) { + PrintKernel("NVMe: Successfully initialized NVMe controller\n"); + BlockDeviceDetectAndRegisterPartitions(nvme_device); + return 0; + } + + PrintKernel("NVMe: Failed to register block device\n"); + return -1; +} \ No newline at end of file diff --git a/drivers/storage/NVMe.h b/drivers/storage/NVMe.h new file mode 100644 index 0000000..46b2126 --- /dev/null +++ b/drivers/storage/NVMe.h @@ -0,0 +1,107 @@ +#ifndef VOIDFRAME_NVME_H +#define VOIDFRAME_NVME_H + +#include "stdint.h" +#include "PCI/PCI.h" + +// NVMe PCI Class/Subclass +#define NVME_CLASS_CODE 0x01 +#define NVME_SUBCLASS 0x08 +#define NVME_PROG_IF 0x02 + +// NVMe Controller Registers (BAR0 offsets) +#define NVME_CAP 0x00 // Controller Capabilities +#define NVME_VS 0x08 // Version +#define NVME_CC 0x14 // Controller Configuration +#define NVME_CSTS 0x1C // Controller Status +#define NVME_AQA 0x24 // Admin Queue Attributes +#define NVME_ASQ 0x28 // Admin Submission Queue Base +#define NVME_ACQ 0x30 // Admin Completion Queue Base + +// Controller Configuration bits +#define NVME_CC_EN (1 << 0) // Enable +#define NVME_CC_CSS_NVM (0 << 4) // NVM Command Set +#define NVME_CC_MPS_4K (0 << 7) // 4KB Memory Page Size +#define NVME_CC_AMS_RR (0 << 11) // Round Robin +#define NVME_CC_SHN_NONE (0 << 14) // No shutdown +#define NVME_CC_IOSQES_64 (6 << 16) // 64-byte SQ entries +#define NVME_CC_IOCQES_16 (4 << 20) // 16-byte CQ entries + +// Controller Status bits +#define NVME_CSTS_RDY (1 << 0) // Ready +#define NVME_CSTS_CFS (1 << 1) // Controller Fatal Status +#define NVME_CSTS_SHST_MASK (3 << 2) // Shutdown Status + +// NVMe Commands +#define NVME_ADMIN_IDENTIFY 0x06 +#define NVME_CMD_READ 0x02 +#define NVME_CMD_WRITE 0x01 + +// Queue sizes +#define NVME_ADMIN_QUEUE_SIZE 64 +#define NVME_IO_QUEUE_SIZE 256 + +// NVMe Submission Queue Entry +typedef struct { + uint32_t cdw0; // Command Dword 0 + uint32_t nsid; // Namespace ID + uint64_t rsvd2; + uint64_t mptr; // Metadata Pointer + uint64_t prp1; // PRP Entry 1 + uint64_t prp2; // PRP Entry 2 + uint32_t cdw10; + uint32_t cdw11; + uint32_t cdw12; + uint32_t cdw13; + uint32_t cdw14; + uint32_t cdw15; +} __attribute__((packed)) NVMeSubmissionEntry; + +// NVMe Completion Queue Entry +typedef struct { + uint32_t dw0; // Command-specific + uint32_t dw1; // Reserved + uint16_t sq_head; // Submission Queue Head + uint16_t sq_id; // Submission Queue ID + uint16_t cid; // Command ID + uint16_t status; // Status Field +} __attribute__((packed)) NVMeCompletionEntry; + +// NVMe Controller structure +typedef struct { + PciDevice pci_device; + volatile uint8_t* mmio_base; + uint64_t mmio_size; + + // Doorbell parameters + uint8_t dstrd; // CAP.DSTRD value (stride as 2^n of 4-byte units) + + // Admin queues + NVMeSubmissionEntry* admin_sq; + NVMeCompletionEntry* admin_cq; + uint64_t admin_sq_phys; + uint64_t admin_cq_phys; + uint16_t admin_sq_tail; + uint16_t admin_cq_head; + uint8_t admin_cq_phase; + + // I/O queues + NVMeSubmissionEntry* io_sq; + NVMeCompletionEntry* io_cq; + uint64_t io_sq_phys; + uint64_t io_cq_phys; + uint16_t io_sq_tail; + uint16_t io_cq_head; + uint8_t io_cq_phase; + + uint16_t next_cid; + uint32_t namespace_size; + int initialized; +} NVMeController; + +// Function prototypes +int NVMe_Init(void); +int NVMe_ReadSectors(uint64_t lba, uint16_t count, void* buffer); +int NVMe_WriteSectors(uint64_t lba, uint16_t count, const void* buffer); + +#endif // VOIDFRAME_NVME_H \ No newline at end of file diff --git a/fs/EXT/Ext2.c b/fs/EXT/Ext2.c index bb57f6f..1bbbc10 100644 --- a/fs/EXT/Ext2.c +++ b/fs/EXT/Ext2.c @@ -24,7 +24,27 @@ typedef struct { RustRwLock* lock; } Ext2Volume; -static Ext2Volume volume; +// Per-device volume registry and active context +static Ext2Volume* g_ext2_by_dev[MAX_BLOCK_DEVICES] = {0}; +static Ext2Volume* g_ext2_active = NULL; +#define volume (*g_ext2_active) + +void Ext2SetActive(BlockDevice* device) { + if (device == NULL) { + g_ext2_active = NULL; + return; + } + int id = device->id; + if (id < 0 || id >= MAX_BLOCK_DEVICES) { + g_ext2_active = NULL; + return; + } + Ext2Volume* vol = g_ext2_by_dev[id]; + if (!vol->lock) return; + rust_rwlock_write_lock(vol->lock, GetCurrentProcess()->pid); + g_ext2_active = vol; + rust_rwlock_write_unlock(vol->lock); +} int Ext2Detect(BlockDevice* device) { PrintKernel("EXT2: Detecting EXT2 on device "); @@ -101,6 +121,27 @@ int Ext2ReadBlock(uint32_t block, void* buffer) { static FileSystemDriver ext2_driver = {"EXT2", Ext2Detect, Ext2Mount}; int Ext2Mount(BlockDevice* device, const char* mount_point) { + // Prepare or reuse per-device volume + if (device == NULL) { + PrintKernelF("EXT2: Mount called with NULL device.\n"); + return -1; + } + if (device->id < 0 || device->id >= MAX_BLOCK_DEVICES) { + PrintKernelF("EXT2: Invalid device id %d.\n", device->id); + return -1; + } + Ext2Volume* vol = g_ext2_by_dev[device->id]; + if (!vol) { + vol = (Ext2Volume*)KernelMemoryAlloc(sizeof(Ext2Volume)); + if (!vol) { + PrintKernelF("EXT2: Failed to allocate volume structure.\n"); + return -1; + } + FastMemset(vol, 0, sizeof(Ext2Volume)); + g_ext2_by_dev[device->id] = vol; + } + g_ext2_active = vol; // Set active for init path below via `volume` macro + if (!volume.lock) volume.lock = rust_rwlock_new(); if (!volume.lock) { PrintKernelF("EXT2: Failed to allocate lock.\n"); @@ -536,8 +577,6 @@ int Ext2ListDir(const char* path) { return -1; } - PrintKernelF("Listing directory: %s\n", path); - // Direct blocks only for (int i = 0; i < 12; i++) { if (inode.i_block[i] == 0) continue; diff --git a/fs/EXT/Ext2.h b/fs/EXT/Ext2.h index da2e541..1413547 100644 --- a/fs/EXT/Ext2.h +++ b/fs/EXT/Ext2.h @@ -102,6 +102,8 @@ typedef struct { // Function prototypes for VFS integration int Ext2Mount(BlockDevice* device, const char* mount_point); int Ext2Detect(BlockDevice* device); +// Set the active EXT2 volume context for subsequent EXT2 operations +void Ext2SetActive(BlockDevice* device); int Ext2ReadFile(const char* path, void* buffer, uint32_t max_size); int Ext2WriteFile(const char* path, const void* buffer, uint32_t size); int Ext2ListDir(const char* path); diff --git a/fs/FAT/FAT1x.c b/fs/FAT/FAT1x.c index 91264be..0124c4b 100644 --- a/fs/FAT/FAT1x.c +++ b/fs/FAT/FAT1x.c @@ -8,9 +8,19 @@ #include "StringOps.h" #include "VFS.h" -static Fat1xVolume volume; +// Per-device volume registry and active context +static Fat1xVolume* g_fat1x_by_dev[MAX_BLOCK_DEVICES] = {0}; +static Fat1xVolume* g_fat1x_active = NULL; +#define volume (*g_fat1x_active) static uint8_t* sector_buffer = NULL; +void Fat1xSetActive(BlockDevice* device) { + if (!device) { g_fat1x_active = NULL; return; } + int id = device->id; + if (id < 0 || id >= MAX_BLOCK_DEVICES) { g_fat1x_active = NULL; return; } + g_fat1x_active = g_fat1x_by_dev[id]; +} + int Fat1xDetect(BlockDevice* device) { uint8_t boot_sector[512]; if (BlockDeviceRead(device->id, 0, 1, boot_sector) != 0) { @@ -34,6 +44,16 @@ int Fat1xDetect(BlockDevice* device) { static FileSystemDriver fat_driver = {"FAT1x", Fat1xDetect, Fat1xMount}; int Fat1xMount(BlockDevice* device, const char* mount_point) { + if (!device) return -1; + if (device->id < 0 || device->id >= MAX_BLOCK_DEVICES) return -1; + Fat1xVolume* vol = g_fat1x_by_dev[device->id]; + if (!vol) { + vol = (Fat1xVolume*)KernelMemoryAlloc(sizeof(Fat1xVolume)); + if (!vol) return -1; + FastMemset(vol, 0, sizeof(Fat1xVolume)); + g_fat1x_by_dev[device->id] = vol; + } + g_fat1x_active = vol; volume.device = device; // Read boot sector diff --git a/fs/FAT/FAT1x.h b/fs/FAT/FAT1x.h index f2f931d..7950ab3 100644 --- a/fs/FAT/FAT1x.h +++ b/fs/FAT/FAT1x.h @@ -63,6 +63,8 @@ typedef struct { // Core Functions int Fat1xMount(BlockDevice* device, const char* mount_point); int Fat1xDetect(BlockDevice* device); +// Set the active FAT1x volume context for subsequent FAT operations +void Fat1xSetActive(BlockDevice* device); int Fat1xReadFile(const char* filename, void* buffer, uint32_t max_size); int Fat1xWriteFile(const char* filename, const void* buffer, uint32_t size); int Fat1xDeleteFile(const char* filename); diff --git a/fs/NTFS/NTFS.c b/fs/NTFS/NTFS.c index e34f0cd..c82f149 100644 --- a/fs/NTFS/NTFS.c +++ b/fs/NTFS/NTFS.c @@ -19,7 +19,16 @@ typedef struct { RustRwLock* lock; } NtfsVolume; -static NtfsVolume volume; +static NtfsVolume* g_ntfs_by_dev[MAX_BLOCK_DEVICES] = {0}; +static NtfsVolume* g_ntfs_active = NULL; +#define volume (*g_ntfs_active) + +void NtfsSetActive(BlockDevice* device) { + if (!device) { g_ntfs_active = NULL; return; } + int id = device->id; + if (id < 0 || id >= MAX_BLOCK_DEVICES) { g_ntfs_active = NULL; return; } + g_ntfs_active = g_ntfs_by_dev[id]; +} int NtfsDetect(struct BlockDevice* device) { if (!device || !device->read_blocks) return 0; @@ -38,7 +47,16 @@ static FileSystemDriver ntfs_driver = {"NTFS", NtfsDetect, NtfsMount}; int NtfsMount(struct BlockDevice* device, const char* mount_point) { if (!device || !device->read_blocks) return -1; - + if (device->id < 0 || device->id >= MAX_BLOCK_DEVICES) return -1; + NtfsVolume* vol = g_ntfs_by_dev[device->id]; + if (!vol) { + vol = (NtfsVolume*)KernelMemoryAlloc(sizeof(NtfsVolume)); + if (!vol) return -1; + FastMemset(vol, 0, sizeof(NtfsVolume)); + g_ntfs_by_dev[device->id] = vol; + } + g_ntfs_active = vol; + if (!volume.lock) volume.lock = rust_rwlock_new(); if (!volume.lock) { PrintKernel("NTFS: Failed to allocate lock\n"); diff --git a/fs/NTFS/NTFS.h b/fs/NTFS/NTFS.h index 0df490f..66f83c0 100644 --- a/fs/NTFS/NTFS.h +++ b/fs/NTFS/NTFS.h @@ -142,6 +142,7 @@ uint64_t NtfsGetFileSize(const char* path); int NtfsCreateFile(const char* path); int NtfsCreateDir(const char* path); int NtfsDelete(const char* path); +void NtfsSetActive(BlockDevice* device); // Internal Functions int NtfsReadMftRecord(uint64_t record_num, NtfsMftRecord* record); diff --git a/fs/VFS.c b/fs/VFS.c index dae6e84..fec535d 100644 --- a/fs/VFS.c +++ b/fs/VFS.c @@ -146,10 +146,13 @@ int VfsReadFile(const char* path, void* buffer, uint32_t max_size) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xReadFile(local_path, buffer, max_size); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2ReadFile(local_path, buffer, max_size); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsReadFile(local_path, buffer, max_size); } } else { @@ -174,10 +177,13 @@ int VfsWriteFile(const char* path, const void* buffer, uint32_t size) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xWriteFile(local_path, buffer, size); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2WriteFile(local_path, buffer, size); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsWriteFile(local_path, buffer, size); } } else { @@ -200,10 +206,13 @@ int VfsListDir(const char* path) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xListDirectory(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2ListDir(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsListDir(local_path); } } else { @@ -222,10 +231,13 @@ int VfsCreateFile(const char* path) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xCreateFile(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2CreateFile(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsCreateFile(local_path); } } else { @@ -247,10 +259,13 @@ int VfsCreateDir(const char* path) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xCreateDir(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2CreateDir(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsCreateDir(local_path); } } else { @@ -269,11 +284,14 @@ int VfsDelete(const char* path, bool Recursive) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); if (Recursive) return Fat1xDeleteRecursive(local_path); return Fat1xDeleteFile(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2Delete(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsDelete(local_path); } } else { @@ -293,10 +311,13 @@ int VfsIsDir(const char* path) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xIsDirectory(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2IsDir(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsIsDir(local_path); } } else { @@ -318,8 +339,10 @@ int VfsIsFile(const char* path) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { return Fat1xGetFileSize(local_path) > 0; } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2IsFile(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsIsFile(local_path); } } else { @@ -339,10 +362,13 @@ uint64_t VfsGetFileSize(const char* path) { if (mount->fs_driver) { if (FastStrCmp(mount->fs_driver->name, "FAT1x") == 0) { + Fat1xSetActive(mount->device); return Fat1xGetFileSize(local_path); } else if (FastStrCmp(mount->fs_driver->name, "EXT2") == 0) { + Ext2SetActive(mount->device); return Ext2GetFileSize(local_path); } else if (FastStrCmp(mount->fs_driver->name, "NTFS") == 0) { + NtfsSetActive(mount->device); return NtfsGetFileSize(local_path); } } else { diff --git a/include/Vector.h b/include/Vector.h new file mode 100644 index 0000000..3160258 --- /dev/null +++ b/include/Vector.h @@ -0,0 +1,192 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include "stdbool.h" +#include "Panic.h" +#include "KernelHeap.h" +#include "MemOps.h" + +/* Generic vector implementation in C with pseudo dot-syntax */ + +/* Define vector operations struct - this holds our "methods" */ +#define VECTOR_OPS(T) \ + struct vector_ops_##T { \ + void (*push_back)(void*, T); \ + void (*pop_back)(void*); \ + T (*at)(void*, size_t); \ + T* (*get)(void*, size_t); \ + size_t (*size)(void*); \ + size_t (*capacity)(void*); \ + void (*clear)(void*); \ + void (*resize)(void*, size_t); \ + void (*reserve)(void*, size_t); \ + int (*empty)(void*); \ + T (*front)(void*); \ + T (*back)(void*); \ + void (*destroy)(void*); \ + } + +/* Define the vector structure */ +#define VECTOR(T) \ + struct vector_##T { \ + T* data; \ + size_t size; \ + size_t capacity; \ + struct vector_ops_##T ops; \ + } + +/* Forward declare all functions for a type */ +#define VECTOR_DECLARE(T) \ + VECTOR_OPS(T); \ + VECTOR(T); \ + void vector_##T##_push_back(void* v, T val); \ + void vector_##T##_pop_back(void* v); \ + T vector_##T##_at(void* v, size_t idx); \ + T* vector_##T##_get(void* v, size_t idx); \ + size_t vector_##T##_size(void* v); \ + size_t vector_##T##_capacity(void* v); \ + void vector_##T##_clear(void* v); \ + void vector_##T##_resize(void* v, size_t new_size); \ + void vector_##T##_reserve(void* v, size_t new_cap); \ + int vector_##T##_empty(void* v); \ + T vector_##T##_front(void* v); \ + T vector_##T##_back(void* v); \ + void vector_##T##_destroy(void* v); \ + struct vector_##T vector_##T##_init(void); + +/* Define all vector functions for a type */ +#define VECTOR_DEFINE(T) \ + void vector_##T##_push_back(void* v, T val) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + if (vec->size >= vec->capacity) { \ + size_t new_cap = vec->capacity == 0 ? 1 : vec->capacity * 2; \ + vector_##T##_reserve(v, new_cap); \ + } \ + vec->data[vec->size++] = val; \ + } \ + \ + void vector_##T##_pop_back(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + if (vec->size > 0) vec->size--; \ + } \ + \ + T vector_##T##_at(void* v, size_t idx) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + ASSERT(idx < vec->size && "Index out of bounds"); \ + return vec->data[idx]; \ + } \ + \ + T* vector_##T##_get(void* v, size_t idx) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + ASSERT(idx < vec->size && "Index out of bounds"); \ + return &vec->data[idx]; \ + } \ + \ + size_t vector_##T##_size(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + return vec->size; \ + } \ + \ + size_t vector_##T##_capacity(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + return vec->capacity; \ + } \ + \ + void vector_##T##_clear(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + vec->size = 0; \ + } \ + \ + void vector_##T##_resize(void* v, size_t new_size) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + if (new_size > vec->capacity) { \ + vector_##T##_reserve(v, new_size); \ + } \ + vec->size = new_size; \ + } \ + \ + void vector_##T##_reserve(void* v, size_t new_cap) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + if (new_cap > vec->capacity) { \ + T* new_data = (T*)KernelMemoryAlloc(new_cap * sizeof(T)); \ + if (vec->data) { \ + FastMemcpy(new_data, vec->data, vec->size * sizeof(T)); \ + KernelFree(vec->data); \ + } \ + vec->data = new_data; \ + vec->capacity = new_cap; \ + } \ + } \ + \ + int vector_##T##_empty(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + return vec->size == 0; \ + } \ + \ + T vector_##T##_front(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + ASSERT(vec->size > 0 && "Vector is empty"); \ + return vec->data[0]; \ + } \ + \ + T vector_##T##_back(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + ASSERT(vec->size > 0 && "Vector is empty"); \ + return vec->data[vec->size - 1]; \ + } \ + \ + void vector_##T##_destroy(void* v) { \ + struct vector_##T* vec = (struct vector_##T*)v; \ + if (vec->data) { \ + KernelFree(vec->data); \ + vec->data = NULL; \ + } \ + vec->size = 0; \ + vec->capacity = 0; \ + } \ + \ + struct vector_##T vector_##T##_init(void) { \ + struct vector_##T vec = { \ + .data = NULL, \ + .size = 0, \ + .capacity = 0, \ + .ops = { \ + .push_back = vector_##T##_push_back, \ + .pop_back = vector_##T##_pop_back, \ + .at = vector_##T##_at, \ + .get = vector_##T##_get, \ + .size = vector_##T##_size, \ + .capacity = vector_##T##_capacity, \ + .clear = vector_##T##_clear, \ + .resize = vector_##T##_resize, \ + .reserve = vector_##T##_reserve, \ + .empty = vector_##T##_empty, \ + .front = vector_##T##_front, \ + .back = vector_##T##_back, \ + .destroy = vector_##T##_destroy \ + } \ + }; \ + return vec; \ + } + +/* Convenience macros for initialization and type naming */ +#define vector(T) struct vector_##T +#define vector_init(T) vector_##T##_init() + +/* Macro for array-like access */ +#define vec_at(vec, idx) ((vec).data[idx]) + +/* Alternative approach using compound literals for even cleaner syntax */ +#define VECTOR_NEW(T) ({ \ + struct vector_##T* v = KernelMemoryAlloc(sizeof(struct vector_##T)); \ + *v = vector_##T##_init(); \ + v; \ +}) + +#define VECTOR_FREE(v) do { \ + (v)->ops.destroy(v); \ + KernelFree(v); \ +} while(0) + + +#endif /* VECTOR_H */ \ No newline at end of file diff --git a/include/math.h b/include/math.h index 42be8d2..80102ef 100644 --- a/include/math.h +++ b/include/math.h @@ -30,6 +30,10 @@ #define isnormal(x) __builtin_isnormal(x) #define signbit(x) __builtin_signbit(x) +static inline int abs(const int x) { + return x < 0 ? -x : x; +} + /* Fast absolute value using bit manipulation */ static inline double fabs(double x) { union { double d; uint64_t i; } u = { x }; @@ -258,20 +262,6 @@ static inline float fast_sinf(float x) { return x * (1.0f - x2 * (0.16666667f - x2 * (0.00833333f - x2 * 0.0001984f))); } -/* Inverse trig using Newton-Raphson */ -static inline double asin(double x) { - if (x < -1 || x > 1) return NAN; - if (x == 1) return M_PI_2; - if (x == -1) return -M_PI_2; - - // Use identity: asin(x) = atan(x/sqrt(1-x^2)) - return atan2(x, sqrt(1 - x * x)); -} - -static inline double acos(double x) { - if (x < -1 || x > 1) return NAN; - return M_PI_2 - asin(x); -} static inline double atan(double x) { int invert = 0, complement = 0; @@ -290,6 +280,7 @@ static inline double atan(double x) { return copysign(result, x); } + static inline double atan2(double y, double x) { if (x > 0) return atan(y / x); if (x < 0 && y >= 0) return atan(y / x) + M_PI; @@ -299,6 +290,21 @@ static inline double atan2(double y, double x) { return 0; // x == 0 && y == 0 } +/* Inverse trig using Newton-Raphson */ +static inline double asin(double x) { + if (x < -1 || x > 1) return NAN; + if (x == 1) return M_PI_2; + if (x == -1) return -M_PI_2; + + // Use identity: asin(x) = atan(x/sqrt(1-x^2)) + return atan2(x, sqrt(1 - x * x)); +} + +static inline double acos(double x) { + if (x < -1 || x > 1) return NAN; + return M_PI_2 - asin(x); +} + /* Hyperbolic functions */ static inline double sinh(double x) { double e = exp(x); diff --git a/include/stdlib.h b/include/stdlib.h index 91ef196..e0526ae 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -1,20 +1,6 @@ #ifndef VOIDFRAME_STDLIB_H #define VOIDFRAME_STDLIB_H -static inline int ABSi(const int x) { - if (x < 0) { - return -x; - } - return x; -} - -static inline double ABSd(const double x) { - if (x < 0.0) { - return -x; - } - return x; -} - static inline int atoi(const char* str) { int result = 0; int sign = 1; @@ -43,12 +29,4 @@ static inline int atoi(const char* str) { return result * sign; } -static inline double pow(double base, double exp) { - double result = 1.0; - for (int i = 0; i < exp; i++) { - result *= base; - } - return result; -} - #endif // VOIDFRAME_STDLIB_H diff --git a/kernel/core/Kernel.c b/kernel/core/Kernel.c index 9358708..5236f11 100644 --- a/kernel/core/Kernel.c +++ b/kernel/core/Kernel.c @@ -30,12 +30,14 @@ #include "VFRFS.h" #include "VFS.h" #include "VMem.h" +#include "Vector.h" #include "Vesa.h" #include "ethernet/Network.h" #include "sound/Generic.h" #include "stdbool.h" #include "stdint.h" #include "storage/AHCI.h" +#include "storage/NVMe.h" #include "xHCI/xHCI.h" void KernelMainHigherHalf(void); @@ -690,6 +692,14 @@ static InitResultT PXS2(void) { } #endif +#ifdef VF_CONFIG_ENABLE_NVME + if (NVMe_Init() == 0) { + PrintKernelSuccess("System: NVMe Driver initialized\n"); + } else { + PrintKernelWarning("NVMe initialization failed\n"); + } +#endif + // Initialize RFS PrintKernel("Info: Initializing RFS...\n"); FsInit(); @@ -732,7 +742,7 @@ void StackUsage(void) { uintptr_t current_sp; __asm__ __volatile__("mov %%rsp, %0" : "=r"(current_sp)); size_t used = (uintptr_t)kernel_stack + KERNEL_STACK_SIZE - current_sp; - PrintKernelF("Stack used: %lu/%d bytes\n", used, KERNEL_STACK_SIZE); + PrintKernelF("Stack used: %llu/%d bytes\n", used, KERNEL_STACK_SIZE); } asmlinkage void KernelMain(const uint32_t magic, const uint32_t info) { diff --git a/kernel/etc/Format.c b/kernel/etc/Format.c index 0b3ece1..a53dcc1 100644 --- a/kernel/etc/Format.c +++ b/kernel/etc/Format.c @@ -75,212 +75,165 @@ unsigned long __rem = (unsigned long)(n) % (unsigned long)(base); \ (unsigned int)__rem; }) #endif -static char* number(char* str, long num, int base, int size, int precision, int type) +static void number_to_str(char* buf, size_t buf_size, int* pos, unsigned long long num, int base, int flags) { - char c,sign,tmp[36]; - const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - int i; - - if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; - if (type&LEFT) type &= ~ZEROPAD; - if (base<2 || base>36) - return 0; - c = (type & ZEROPAD) ? '0' : ' ' ; - if (type&SIGN && num<0) { - sign='-'; - num = -num; - } else - sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); - if (sign) size--; - if (type&SPECIAL) - if (base==16) size -= 2; - else if (base==8) size--; - i=0; - if (num==0) - tmp[i++]='0'; - else while (num!=0) - tmp[i++]=digits[do_div(num,base)]; - if (i>precision) precision=i; - size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) - *str++ = ' '; - if (sign) - *str++ = sign; - if (type&SPECIAL) - if (base==8) - *str++ = '0'; - else if (base==16) { - *str++ = '0'; - *str++ = digits[33]; + char tmp[24]; + const char *digits = (flags & SMALL) ? "0123456789abcdefghijklmnopqrstuvwxyz" : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i = 0; + + if (num == 0) { + tmp[i++] = '0'; + } else { + while (num && i < 23) { + tmp[i++] = digits[num % base]; + num /= base; } - if (!(type&LEFT)) - while(size-->0) - *str++ = c; - while(i0) - *str++ = tmp[i]; - while(size-->0) - *str++ = ' '; - return str; + } + + while (i > 0 && *pos < (int)buf_size - 1) { + buf[(*pos)++] = tmp[--i]; + } } -int vsprintf(char *buf, const char *fmt, va_list args) +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { - int len; - int i; - char * str; - char *s; - int *ip; + int pos = 0; + const char *s; + int len, i; + int flags; - int flags; /* flags to number() */ + if (!buf || size == 0) return 0; - int field_width; /* width of output field */ - int precision; /* min. # of digits for integers; max - number of chars for from string */ - int qualifier; /* 'h', 'l', or 'L' for integer fields */ - - for (str=buf ; *fmt ; ++fmt) { + for (; *fmt && pos < (int)size - 1; ++fmt) { if (*fmt != '%') { - *str++ = *fmt; + buf[pos++] = *fmt; continue; } - /* process flags */ + ++fmt; flags = 0; - repeat: - ++fmt; /* this also skips first '%' */ - switch (*fmt) { - case '-': flags |= LEFT; goto repeat; - case '+': flags |= PLUS; goto repeat; - case ' ': flags |= SPACE; goto repeat; - case '#': flags |= SPECIAL; goto repeat; - case '0': flags |= ZEROPAD; goto repeat; - } - - /* get field width */ - field_width = -1; - if (is_digit(*fmt)) - field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - field_width = va_arg(args, int); - if (field_width < 0) { - field_width = -field_width; - flags |= LEFT; - } + + /* Skip flags */ + while (*fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#' || *fmt == '0') { + if (*fmt == 'x') flags |= SMALL; + ++fmt; } - /* get the precision */ - precision = -1; + /* Skip field width */ + while (is_digit(*fmt)) ++fmt; + + /* Skip precision */ if (*fmt == '.') { ++fmt; - if (is_digit(*fmt)) - precision = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - precision = va_arg(args, int); - } - if (precision < 0) - precision = 0; + while (is_digit(*fmt)) ++fmt; } - /* get the conversion qualifier */ - qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { - qualifier = *fmt; + /* Parse length modifier */ + int is_long = 0, is_longlong = 0; + if (*fmt == 'l') { + ++fmt; + is_long = 1; + if (*fmt == 'l') { + ++fmt; + is_longlong = 1; + is_long = 0; + } + } else if (*fmt == 'h' || *fmt == 'L') { ++fmt; } switch (*fmt) { case 'c': - if (!(flags & LEFT)) - while (--field_width > 0) - *str++ = ' '; - *str++ = (unsigned char) va_arg(args, int); - while (--field_width > 0) - *str++ = ' '; + if (pos < (int)size - 1) buf[pos++] = (char)va_arg(args, int); break; case 's': s = va_arg(args, char *); - if (!s) - s = ""; + if (!s) s = "(null)"; len = StringLength(s); - if (precision < 0) - precision = len; - else if (len > precision) - len = precision; - - if (!(flags & LEFT)) - while (len < field_width--) - *str++ = ' '; - for (i = 0; i < len; ++i) - *str++ = *s++; - while (len < field_width--) - *str++ = ' '; + for (i = 0; i < len && pos < (int)size - 1; i++) { + buf[pos++] = s[i]; + } break; - case 'o': - str = number(str, va_arg(args, unsigned long), 8, - field_width, precision, flags); + case 'd': + case 'i': { + long long snum; + if (is_longlong) snum = va_arg(args, long long); + else if (is_long) snum = va_arg(args, long); + else snum = va_arg(args, int); + + if (snum < 0 && pos < (int)size - 1) { + buf[pos++] = '-'; + snum = -snum; + } + number_to_str(buf, size, &pos, (unsigned long long)snum, 10, 0); break; + } - case 'p': - if (field_width == -1) { - field_width = 8; - flags |= ZEROPAD; - } - str = number(str, - (unsigned long) va_arg(args, void *), 16, - field_width, precision, flags); + case 'u': { + unsigned long long unum; + if (is_longlong) unum = va_arg(args, unsigned long long); + else if (is_long) unum = va_arg(args, unsigned long); + else unum = va_arg(args, unsigned int); + number_to_str(buf, size, &pos, unum, 10, 0); break; + } case 'x': flags |= SMALL; - case 'X': - str = number(str, va_arg(args, unsigned long), 16, - field_width, precision, flags); + case 'X': { + unsigned long long unum; + if (is_longlong) unum = va_arg(args, unsigned long long); + else if (is_long) unum = va_arg(args, unsigned long); + else unum = va_arg(args, unsigned int); + number_to_str(buf, size, &pos, unum, 16, flags); break; + } - case 'd': - case 'i': - flags |= SIGN; - case 'u': - str = number(str, va_arg(args, unsigned long), 10, - field_width, precision, flags); + case 'o': { + unsigned long long unum; + if (is_longlong) unum = va_arg(args, unsigned long long); + else if (is_long) unum = va_arg(args, unsigned long); + else unum = va_arg(args, unsigned int); + number_to_str(buf, size, &pos, unum, 8, 0); break; + } - case 'n': - ip = va_arg(args, int *); - *ip = (str - buf); + case 'p': + if (pos < (int)size - 1) buf[pos++] = '0'; + if (pos < (int)size - 1) buf[pos++] = 'x'; + number_to_str(buf, size, &pos, (unsigned long long)va_arg(args, void *), 16, SMALL); + break; + + case '%': + if (pos < (int)size - 1) buf[pos++] = '%'; break; default: - if (*fmt != '%') - *str++ = '%'; - if (*fmt) - *str++ = *fmt; - else - --fmt; + if (pos < (int)size - 1) buf[pos++] = '%'; + if (*fmt && pos < (int)size - 1) buf[pos++] = *fmt; break; } } - *str = '\0'; - return str-buf; + + buf[pos] = '\0'; + return pos; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return vsnprintf(buf, 0x7FFFFFFF, fmt, args); } int Format(char* buffer, size_t size, const char* format, va_list args) { - (void)size; - return vsprintf(buffer, format, args); + return vsnprintf(buffer, size, format, args); } -// Convenience wrapper int FormatA(char* buffer, size_t size, const char* format, ...) { va_list args; va_start(args, format); - int result = vsprintf(buffer, format, args); + int result = vsnprintf(buffer, size, format, args); va_end(args); return result; } @@ -289,7 +242,7 @@ char* FormatS(const char* format, ...) { static char stack_buffer[1024]; va_list args; va_start(args, format); - vsprintf(stack_buffer, format, args); + vsnprintf(stack_buffer, sizeof(stack_buffer), format, args); va_end(args); return stack_buffer; -} +} \ No newline at end of file diff --git a/kernel/etc/Format.h b/kernel/etc/Format.h index 1116007..0f0e974 100644 --- a/kernel/etc/Format.h +++ b/kernel/etc/Format.h @@ -2,7 +2,7 @@ #include "stdarg.h" #include "stddef.h" -#define FORMAT_STACK_SIZE 2048 +#define FORMAT_STACK_SIZE 1024 /** * @brief Formats a string according to the given format string and variable argument list, @@ -37,6 +37,7 @@ int Format(char* buffer, size_t size, const char* format, va_list args); /** + * @alias vsnprintf * @brief Convenience wrapper for the Format (...) function using variable arguments. * @param buffer Buffer to the character out * @param size size of buffer diff --git a/kernel/etc/StringOps.c b/kernel/etc/StringOps.c index 3d8894f..de0265f 100644 --- a/kernel/etc/StringOps.c +++ b/kernel/etc/StringOps.c @@ -1,4 +1,3 @@ -// #include "StringOps.h" #include "KernelHeap.h" int StringLength(const char* str) { // simpler than FasStrlen, @@ -211,3 +210,71 @@ char* strtok(char* s, char d) { return result; } +/** + * strspn - Calculate the length of the initial substring of @s which only + * contain letters in @accept + * @s: The string to be searched + * @accept: The string to search for + */ +size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} + +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ +char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) { + for( sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *) sc1; + } + } + return NULL; +} + +/** + * strsep - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * strsep() updates @s to point after the token, ready for the next call. + * + * It returns empty tokens, too, behaving exactly like the libc function + * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. + * Same semantics, slimmer shape. ;) + */ +char * strsep(char **s, const char *ct) +{ + char *sbegin = *s, *end; + + if (sbegin == NULL) + return NULL; + + end = strpbrk(sbegin, ct); + if (end) + *end++ = '\0'; + *s = end; + + return sbegin; +} \ No newline at end of file diff --git a/kernel/etc/StringOps.h b/kernel/etc/StringOps.h index d0a373c..f4fcd22 100644 --- a/kernel/etc/StringOps.h +++ b/kernel/etc/StringOps.h @@ -9,11 +9,13 @@ extern const char* FastStrChr(const char* str, int c); extern int StringLength(const char* str); extern int FastStrnCmp(const char* str1, const char* str2, size_t n); extern char* strtok(char* s, char d); - extern void strncpy(char* dest, const char* src, size_t max_len); extern void strcpy(char* dest, const char* src); extern void strcat(char* dest, const char* src); extern void htoa(uint64_t n, char* buffer); extern void itoa(uint64_t n, char* buffer); +extern char * strsep(char **s, const char *ct); +extern char * strpbrk(const char * cs,const char * ct); +extern size_t strspn(const char *s, const char *accept); #endif // VOIDFRAME_STRINGOPS_H diff --git a/kernel/sched/EEVDF.c b/kernel/sched/EEVDF.c index b14f221..6f0531e 100644 --- a/kernel/sched/EEVDF.c +++ b/kernel/sched/EEVDF.c @@ -1324,7 +1324,7 @@ void EEVDFDumpSchedulerState(void) { void EEVDFListProcesses(void) { PrintKernel("\n--- EEVDF Process List ---\n"); PrintKernel("PID\tState \tNice\tWeight\tVRuntime\tCPU Time\tName\n"); - PrintKernel("---------------------------------------------------------------\n"); + PrintKernel("-------------------------------------------------------------------------------\n"); for (int i = 0; i < EEVDF_MAX_PROCESSES; i++) { if (i == 0 || processes[i].pid != 0) { @@ -1354,7 +1354,7 @@ void EEVDFListProcesses(void) { PrintKernel("\n"); } } - PrintKernel("---------------------------------------------------------------\n"); + PrintKernel("-------------------------------------------------------------------------------\n"); } void EEVDFGetProcessStats(uint32_t pid, uint32_t* cpu_time, uint32_t* wait_time, uint32_t* preemptions) { diff --git a/kernel/sched/MLFQ.c b/kernel/sched/MLFQ.c index 68f9387..014e76b 100644 --- a/kernel/sched/MLFQ.c +++ b/kernel/sched/MLFQ.c @@ -20,6 +20,7 @@ #include "StackGuard.h" #include "VFS.h" #include "VMem.h" +#include "math.h" #include "stdbool.h" #include "stdlib.h" #include "x64.h" @@ -1452,7 +1453,7 @@ static __attribute__((visibility("hidden"))) void DynamoX(void) { uint32_t change_threshold = (controller.stability_counter > STABILITY_REQUIREMENT) ? HYSTERESIS_THRESHOLD / 2 : HYSTERESIS_THRESHOLD; - if (ABSi(new_freq - controller.current_freq) > change_threshold) { + if (abs(new_freq - controller.current_freq) > change_threshold) { ApicTimerSetFrequency(new_freq); controller.current_freq = new_freq; controller.stability_counter = 0;