From 62763050be3a5a28be19eb25f70ada856a9d64d9 Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 1 Sep 2025 14:10:18 +0700 Subject: [PATCH 1/4] VirtIO --- drivers/PCI/PCI.c | 24 +++- drivers/virtio/Virtio.h | 102 ++++++++++++++++ drivers/virtio/VirtioBlk.c | 242 +++++++++++++++++++++++++++++++++++++ drivers/virtio/VirtioBlk.h | 12 ++ fs/FAT12.c | 2 +- kernel/core/Kernel.c | 33 +++-- meson.build | 22 +++- 7 files changed, 425 insertions(+), 12 deletions(-) create mode 100644 drivers/virtio/Virtio.h create mode 100644 drivers/virtio/VirtioBlk.c create mode 100644 drivers/virtio/VirtioBlk.h diff --git a/drivers/PCI/PCI.c b/drivers/PCI/PCI.c index 8f6ebaa..74d10f1 100644 --- a/drivers/PCI/PCI.c +++ b/drivers/PCI/PCI.c @@ -4,6 +4,8 @@ #include "Cpu.h" #include "stdbool.h" #include "stdint.h" +#include "virtio/Virtio.h" +#include "virtio/VirtioBlk.h" static uint8_t target_class; static uint8_t target_subclass; @@ -23,7 +25,8 @@ uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off } uint8_t PciConfigReadByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { - return PciConfigReadDWord(bus, slot, func, offset) & 0xFF; + uint32_t dword = PciConfigReadDWord(bus, slot, func, offset & 0xFC); + return (dword >> ((offset & 3) * 8)) & 0xFF; } void PciConfigWriteDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t data) { @@ -90,6 +93,20 @@ static void PciScanBus(PciDeviceCallback callback) { } } +static void PciVirtioHandler(PciDevice device) { + if (device.vendor_id == VIRTIO_VENDOR_ID) { + PrintKernel("Found VirtIO Device -> DID: 0x"); + PrintKernelHex(device.device_id); + PrintKernel("\n"); + + // 0x1001 is the transitional block device. + // 0x1042 is the modern block device. + if (device.device_id == 0x1042 || device.device_id == 0x1001) { // VirtIO Block Device + InitializeVirtioBlk(device); + } + } +} + // Your old PciEnumerate function, now a simple wrapper around the scanner static void PrintPciDeviceInfo(PciDevice device) { PrintKernel("PCI: B:0x"); PrintKernelHex(device.bus); @@ -105,6 +122,9 @@ static void PrintPciDeviceInfo(PciDevice device) { void PciEnumerate() { PrintKernel("--- PCI Bus Enumeration ---\n"); PciScanBus(PrintPciDeviceInfo); +#ifdef VF_CONFIG_ENABLE_VIRTIO + PciScanBus(PciVirtioHandler); +#endif PrintKernel("---------------------------\n"); } @@ -236,4 +256,4 @@ uint64_t GetPCIMMIOSize(const PciDevice* pci_dev, uint32_t bar_value) { } return size; -} \ No newline at end of file +} diff --git a/drivers/virtio/Virtio.h b/drivers/virtio/Virtio.h new file mode 100644 index 0000000..421c540 --- /dev/null +++ b/drivers/virtio/Virtio.h @@ -0,0 +1,102 @@ +#ifndef VOIDFRAME_VIRTIO_H +#define VOIDFRAME_VIRTIO_H + +#include "stdint.h" + +// Common VirtIO definitions will go here. +// For example, PCI configuration registers, feature bits, status fields, etc. + +#define VIRTIO_VENDOR_ID 0x1AF4 + +// VirtIO PCI Capability IDs +#define VIRTIO_CAP_COMMON_CFG 1 +#define VIRTIO_CAP_NOTIFY_CFG 2 +#define VIRTIO_CAP_ISR_CFG 3 +#define VIRTIO_CAP_DEVICE_CFG 4 +#define VIRTIO_CAP_PCI_CFG 5 + +// VirtIO PCI Capability Structure +struct VirtioPciCap { + uint8_t cap_vndr; // Generic PCI field: PCI_CAP_ID_VNDR + uint8_t cap_next; // Generic PCI field: next ptr + uint8_t cap_len; // Generic PCI field: capability length + uint8_t cfg_type; // Identifies the structure. + uint8_t bar; // Which BAR to find it. + uint8_t padding[3]; + uint32_t offset; // Offset within the BAR. + uint32_t length; // Length of the structure, in bytes. +} __attribute__((packed)); + +// VirtIO Common Configuration Structure (packed for direct mapping) + +struct VirtioPciCommonCfg { + // Device features + uint32_t device_feature_select; + uint32_t device_feature; + // Driver features + uint32_t driver_feature_select; + uint32_t driver_feature; + // MS-X config + uint16_t msix_config; + // Number of queues + uint16_t num_queues; + // Device status + uint8_t device_status; + // Config generation + uint8_t config_generation; + // --- Queue Related --- + uint16_t queue_select; + uint16_t queue_size; + uint16_t queue_msix_vector; + uint16_t queue_enable; + uint16_t queue_notify_off; + uint64_t queue_desc; + uint64_t queue_driver; + uint64_t queue_device; +} __attribute__((packed)); + +// VirtIO Block Device Feature Bits +#define VIRTIO_BLK_F_RO 5 // Device is read-only + +// --- Virtqueue Structures --- + +#define VIRTQ_DESC_F_NEXT 1 // Buffer continues via the next field. +#define VIRTQ_DESC_F_WRITE 2 // Buffer is write-only (device-to-driver). + +struct VirtqDesc { + uint64_t addr; // Physical address + uint32_t len; + uint16_t flags; + uint16_t next; // Index of next descriptor in chain +} __attribute__((packed)); + +struct VirtqAvail { + uint16_t flags; + uint32_t idx; // Where the driver puts the next descriptor index (u32 for atomics) + uint16_t ring[]; // Array of descriptor indices +} __attribute__((packed)); + +struct VirtqUsedElem { + uint32_t id; // Index of the head of the used descriptor chain + uint32_t len; // Total length of the bytes written +} __attribute__((packed)); + +struct VirtqUsed { + uint16_t flags; + uint16_t idx; // Where the device puts the next used descriptor index + struct VirtqUsedElem ring[]; +} __attribute__((packed)); + +// --- VirtIO Block Device Specifics --- + +#define VIRTIO_BLK_T_IN 0 // Read request +#define VIRTIO_BLK_T_OUT 1 // Write request + +struct VirtioBlkReq { + uint32_t type; + uint32_t reserved; + uint64_t sector; +} __attribute__((packed)); + + +#endif //VOIDFRAME_VIRTIO_H diff --git a/drivers/virtio/VirtioBlk.c b/drivers/virtio/VirtioBlk.c new file mode 100644 index 0000000..61a7904 --- /dev/null +++ b/drivers/virtio/VirtioBlk.c @@ -0,0 +1,242 @@ +#include "VirtioBlk.h" + +#include "Atomics.h" +#include "Console.h" +#include "PCI/PCI.h" +#include "VMem.h" +#include "stdbool.h" + +// Globals to hold the capability structures we find +static struct VirtioPciCap cap_common_cfg; +static struct VirtioPciCap cap_notify_cfg; +static struct VirtioPciCap cap_isr_cfg; +static struct VirtioPciCap cap_device_cfg; +static bool have_common_cfg = false; +static bool have_notify_cfg = false; +volatile uint32_t* notify_ptr = NULL; +// --- Virtqueue state --- +static struct VirtqDesc* vq_desc_table; +static struct VirtqAvail* vq_avail_ring; +static struct VirtqUsed* vq_used_ring; +static uint16_t vq_size; +static uint16_t vq_next_desc_idx = 0; +volatile struct VirtioPciCommonCfg* common_cfg_ptr; + +void ReadVirtioCapability(PciDevice device, uint8_t cap_offset, struct VirtioPciCap* cap) { + // cap->cap_vndr is known to be 0x09, not reading + cap->cap_next = PciConfigReadByte(device.bus, device.device, device.function, cap_offset + 1); + cap->cap_len = PciConfigReadByte(device.bus, device.device, device.function, cap_offset + 2); + cap->cfg_type = PciConfigReadByte(device.bus, device.device, device.function, cap_offset + 3); + cap->bar = PciConfigReadByte(device.bus, device.device, device.function, cap_offset + 4); + // cap->padding is bytes 5, 6, 7 + cap->offset = PciConfigReadDWord(device.bus, device.device, device.function, cap_offset + 8); + cap->length = PciConfigReadDWord(device.bus, device.device, device.function, cap_offset + 12); +} + +// Implementation for the VirtIO Block device driver. + +void InitializeVirtioBlk(PciDevice device) { + PrintKernel("VirtIO-Blk: Initializing device at B/D/F "); + PrintKernelHex(device.bus); PrintKernel("/"); PrintKernelHex(device.device); PrintKernel("/"); PrintKernelHex(device.function); + PrintKernel("\n"); + + // Check for capabilities list support + uint16_t status_reg = (PciConfigReadDWord(device.bus, device.device, device.function, 0x04) >> 16); + if (!(status_reg & (1 << 4))) { + PrintKernel("VirtIO-Blk: Error - Device does not support capabilities list.\n"); + return; + } + + // Loop through capabilities + uint8_t cap_pointer = PciConfigReadByte(device.bus, device.device, device.function, 0x34); + while (cap_pointer != 0) { + uint8_t cap_id = PciConfigReadByte(device.bus, device.device, device.function, cap_pointer); + + if (cap_id == 0x09) { // PCI_CAP_ID_VNDR + struct VirtioPciCap temp_cap; + ReadVirtioCapability(device, cap_pointer, &temp_cap); + + switch (temp_cap.cfg_type) { + case VIRTIO_CAP_COMMON_CFG: + cap_common_cfg = temp_cap; + have_common_cfg = true; + break; + case VIRTIO_CAP_NOTIFY_CFG: + cap_notify_cfg = temp_cap; + have_notify_cfg = true; + break; + case VIRTIO_CAP_ISR_CFG: + cap_isr_cfg = temp_cap; + break; + case VIRTIO_CAP_DEVICE_CFG: + cap_device_cfg = temp_cap; + break; + case VIRTIO_CAP_PCI_CFG: + break; + } + } + cap_pointer = PciConfigReadByte(device.bus, device.device, device.function, cap_pointer + 1); + } + + if (!have_common_cfg) { + PrintKernel("VirtIO-Blk: Error - Did not find VIRTIO_CAP_COMMON_CFG.\n"); + return; + } + + // Enable Bus Mastering and memory space on the device + uint16_t command_reg = PciConfigReadDWord(device.bus, device.device, device.function, PCI_COMMAND_REG); + command_reg |= (PCI_CMD_MEM_SPACE_EN | PCI_CMD_BUS_MASTER_EN); + PciConfigWriteDWord(device.bus, device.device, device.function, PCI_COMMAND_REG, command_reg); + + // Get the physical address from the BAR + uint32_t bar_raw = PciConfigReadDWord(device.bus, device.device, device.function, 0x10 + (cap_common_cfg.bar * 4)); + uint64_t phys_addr = bar_raw & 0xFFFFFFF0; + + // Allocate virtual address space for the common config region + void* virt_addr = VMemAlloc(cap_common_cfg.length); + if (!virt_addr) { + PrintKernel("VirtIO-Blk: Error - VMemAlloc failed.\n"); + return; + } + + // Unmap the RAM pages VMemAlloc mapped by default + if (VMemUnmap((uint64_t)virt_addr, cap_common_cfg.length) != VMEM_SUCCESS) { + PrintKernel("VirtIO-Blk: Error - VMemUnmap failed.\n"); + VMemFree(virt_addr, cap_common_cfg.length); + return; + } + + // Map the physical memory into our allocated virtual space + if (VMemMapMMIO((uint64_t)virt_addr, phys_addr, cap_common_cfg.length, VMEM_WRITE | VMEM_NOCACHE) != VMEM_SUCCESS) { + PrintKernel("VirtIO-Blk: Error - VMemMapMMIO failed.\n"); + // Don't VMemFree here as the pages are already unmapped + return; + } + common_cfg_ptr = (struct VirtioPciCommonCfg*)((uint64_t)virt_addr + cap_common_cfg.offset); + + // Map the Notification BAR and get the multiplier + uint32_t notify_off_multiplier = 0; + if (have_notify_cfg) { + uint32_t notify_bar_raw = PciConfigReadDWord(device.bus, device.device, device.function, 0x10 + (cap_notify_cfg.bar * 4)); + uint64_t notify_phys_addr = notify_bar_raw & 0xFFFFFFF0; + void* notify_virt_addr = VMemAlloc(cap_notify_cfg.length); + VMemUnmap((uint64_t)notify_virt_addr, cap_notify_cfg.length); + VMemMapMMIO((uint64_t)notify_virt_addr, notify_phys_addr, cap_notify_cfg.length, VMEM_WRITE | VMEM_NOCACHE); + notify_ptr = (uint32_t*)((uint64_t)notify_virt_addr + cap_notify_cfg.offset); + + // The multiplier is at a different offset within the same BAR, described by another capability. + // For now, we will assume a multiplier of 1, which is common. + // A full implementation would parse the notification capability structure itself. + notify_off_multiplier = 1; + } + + // --- Begin Device Initialization --- + common_cfg_ptr->device_status = 0; // 1. Reset + + common_cfg_ptr->device_status |= (1 << 0); // 2. Set ACKNOWLEDGE bit + common_cfg_ptr->device_status |= (1 << 1); // 3. Set DRIVER bit + + // 4. Feature Negotiation + common_cfg_ptr->driver_feature_select = 0; + uint32_t device_features = common_cfg_ptr->device_feature; + common_cfg_ptr->driver_feature_select = 0; + common_cfg_ptr->driver_feature = 0; + + // 5. Set FEATURES_OK status bit + common_cfg_ptr->device_status |= (1 << 3); + + // 6. Re-read status to ensure device accepted features + uint8_t status = common_cfg_ptr->device_status; + if (!(status & (1 << 3))) { + PrintKernel("VirtIO-Blk: Error - Device rejected features!\n"); + return; + } + + // --- Step 7: Virtqueue Setup --- + common_cfg_ptr->queue_select = 0; + + vq_size = common_cfg_ptr->queue_size; + if (vq_size == 0) { + PrintKernel("VirtIO-Blk: Error - Queue 0 is not available.\n"); + return; + } + + // Allocate memory for the virtqueue components + vq_desc_table = VMemAlloc(sizeof(struct VirtqDesc) * vq_size); + vq_avail_ring = VMemAlloc(sizeof(struct VirtqAvail) + sizeof(uint16_t) * vq_size); + vq_used_ring = VMemAlloc(sizeof(struct VirtqUsed) + sizeof(struct VirtqUsedElem) * vq_size); + + if (!vq_desc_table || !vq_avail_ring || !vq_used_ring) { + PrintKernel("VirtIO-Blk: Error - Failed to allocate memory for virtqueue.\n"); + // TODO: Free allocated memory before returning + return; + } + + // Tell the device the physical addresses of our structures + common_cfg_ptr->queue_desc = VIRT_TO_PHYS((uint64_t)vq_desc_table); + common_cfg_ptr->queue_driver = VIRT_TO_PHYS((uint64_t)vq_avail_ring); + common_cfg_ptr->queue_device = VIRT_TO_PHYS((uint64_t)vq_used_ring); + + // Enable the queue + common_cfg_ptr->queue_enable = 1; + + PrintKernel("VirtIO-Blk: Driver initialized successfully!\n"); +} + +int VirtioBlkRead(uint64_t sector, void* buffer) { + // Step 1: Allocate request header and status byte + struct VirtioBlkReq* req_hdr = VMemAlloc(sizeof(struct VirtioBlkReq)); + uint8_t* status = VMemAlloc(sizeof(uint8_t)); + if (!req_hdr || !status) { + PrintKernel("VirtIO-Blk: Failed to allocate request header/status\n"); + return -1; // Error + } + + // Step 2: Fill out the request header + req_hdr->type = VIRTIO_BLK_T_IN; + req_hdr->reserved = 0; + req_hdr->sector = sector; + + // Step 3: Set up the descriptor chain + uint16_t head_idx = vq_next_desc_idx; + + // Descriptor 1: Request Header (Driver -> Device) + vq_desc_table[head_idx].addr = VIRT_TO_PHYS((uint64_t)req_hdr); + vq_desc_table[head_idx].len = sizeof(struct VirtioBlkReq); + vq_desc_table[head_idx].flags = VIRTQ_DESC_F_NEXT; + vq_desc_table[head_idx].next = head_idx + 1; + + // Descriptor 2: Data Buffer (Device -> Driver) + vq_desc_table[head_idx + 1].addr = VIRT_TO_PHYS((uint64_t)buffer); + vq_desc_table[head_idx + 1].len = 512; // Assume 512-byte sectors + vq_desc_table[head_idx + 1].flags = VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_NEXT; + vq_desc_table[head_idx + 1].next = head_idx + 2; + + // Descriptor 3: Status (Device -> Driver) + vq_desc_table[head_idx + 2].addr = VIRT_TO_PHYS((uint64_t)status); + vq_desc_table[head_idx + 2].len = sizeof(uint8_t); + vq_desc_table[head_idx + 2].flags = VIRTQ_DESC_F_WRITE; + vq_desc_table[head_idx + 2].next = 0; // End of chain + + // Step 4: Add the chain to the available ring + vq_avail_ring->ring[vq_avail_ring->idx % vq_size] = head_idx; + + // Step 5: Update the available ring index atomically + AtomicInc((volatile uint32_t*)&vq_avail_ring->idx); + + // Step 6: Notify the device + if (notify_ptr) { + *(notify_ptr + common_cfg_ptr->queue_notify_off) = 0; // Queue index is 0 + } + + // For now, we just update our internal descriptor index + vq_next_desc_idx = (vq_next_desc_idx + 3) % vq_size; + + // TODO: Add interrupt handling to wait for the read to complete + // and check the status byte. + + // VMemFree(req_hdr, sizeof(struct VirtioBlkReq)); + // VMemFree(status, sizeof(uint8_t)); + + return 0; // Success (for now) +} diff --git a/drivers/virtio/VirtioBlk.h b/drivers/virtio/VirtioBlk.h new file mode 100644 index 0000000..2800240 --- /dev/null +++ b/drivers/virtio/VirtioBlk.h @@ -0,0 +1,12 @@ +#ifndef VOIDFRAME_VIRTIOBLK_H +#define VOIDFRAME_VIRTIOBLK_H + +#include "Virtio.h" +#include "PCI/PCI.h" + +// VirtIO Block device specific definitions and function prototypes. + +void InitializeVirtioBlk(PciDevice device); +int VirtioBlkRead(uint64_t sector, void* buffer); + +#endif //VOIDFRAME_VIRTIOBLK_H diff --git a/fs/FAT12.c b/fs/FAT12.c index 296348f..82e0f44 100644 --- a/fs/FAT12.c +++ b/fs/FAT12.c @@ -577,7 +577,7 @@ int Fat12CreateDir(const char* path) { return -1; } } - KernelFree(cluster_buffer); + // KernelFree(cluster_buffer); - double free? // Update the entry in the parent directory if (IdeReadSector(volume.drive, entry_sector_lba, sector_buffer) != IDE_OK) return -1; diff --git a/kernel/core/Kernel.c b/kernel/core/Kernel.c index 3c2ac9e..7e111a9 100644 --- a/kernel/core/Kernel.c +++ b/kernel/core/Kernel.c @@ -564,11 +564,10 @@ void INITRD1() { // Pre-eXecutionSystem 2 static InitResultT PXS2(void) { +#ifndef VF_CONFIG_VM_HOST // CPU feature validation CPUFeatureValidation(); - - // Memory safety validation - ValidateMemoryLayout(); +#endif // Print bootstrap summary PrintBootstrapSummary(); @@ -619,16 +618,21 @@ static InitResultT PXS2(void) { PitInstall(); PrintKernelSuccess("System: PIC & PIT initialized\n"); +#ifdef VF_CONFIG_ENABLE_PS2 // Initialize keyboard PrintKernel("Info: Initializing keyboard...\n"); PS2Init(); PrintKernelSuccess("System: Keyboard initialized\n"); +#endif +#ifdef VF_CONFIG_USE_VFSHELL // Initialize shell PrintKernel("Info: Initializing shell...\n"); ShellInit(); PrintKernelSuccess("System: Shell initialized\n"); +#endif +#ifdef VF_CONFIG_ENABLE_IDE // Initialize IDE driver PrintKernel("Info: Initializing IDE driver...\n"); const int ide_result = IdeInit(); @@ -646,31 +650,39 @@ static InitResultT PXS2(void) { PrintKernelWarning(" IDE initialization failed - no drives detected\n"); PrintKernelWarning(" Skipping FAT12 initialization\n"); } +#endif // Initialize ram filesystem PrintKernel("Info: Initializing VFRFS...\n"); FsInit(); PrintKernelSuccess("System: VFRFS (VoidFrame RamFS) initialized\n"); +#ifdef VF_CONFIG_ENABLE_INITRD // Initrd INITRD1(); PrintKernelSuccess("System: INITRD (Stage 1) initialized\n"); +#endif // Initialize VFS PrintKernel("Info: Initializing VFS...\n"); VfsInit(); PrintKernelSuccess("System: VFS initialized\n"); - // NEW: Check if huge pages should be enabled +#ifdef VF_CONFIG_ENFORCE_MEMORY_PROTECTION + ValidateMemoryLayout(); PrintKernel("Info: Checking huge page support...\n"); if (!CheckHugePageSupport()) PrintKernel("System: Huge pages not available\n"); else PrintKernelSuccess("System: Huge pages available\n"); +#endif +#ifdef VF_CONFIG_MLFQ_SCHED // Initialize Process Management PrintKernel("Info: Initializing process management...\n"); ProcessInit(); PrintKernelSuccess("System: Process management initialized\n"); +#endif +#ifdef VF_CONFIG_ENABLE_ISA PrintKernel("Info: Initializing ISA bus...\n"); IsaInitBus(); PrintKernelSuccess("System: ISA bus initialized\n"); @@ -678,7 +690,9 @@ static InitResultT PXS2(void) { PrintKernel("Info: Scanning ISA devices...\n"); IsaAutoDetect(); IsaPrintDevices(); +#endif +#ifdef VF_CONFIG_ENABLE_PCI PrintKernel("Info: Scanning PCI devices...\n"); PciEnumerate(); PrintKernelSuccess("System: PCI devices scanned\n"); @@ -686,6 +700,7 @@ static InitResultT PXS2(void) { PrintKernel("Info: Initializing RTL8139 Driver...\n"); Rtl8139_Init(); PrintKernelSuccess("System: RTL8139 Driver initialized\n"); +#endif #ifdef VF_CONFIG_ENABLE_XHCI PrintKernel("Info: Initializing xHCI...\n"); @@ -693,23 +708,25 @@ static InitResultT PXS2(void) { PrintKernelSuccess("System: xHCI initialized\n"); #endif +#ifdef VF_CONFIG_ENABLE_LPT PrintKernel("Info: Initializing LPT Driver...\n"); LPT_Init(); PrintKernelSuccess("System: LPT Driver initialized\n"); +#endif +#ifdef VF_CONFIG_ENFORCE_MEMORY_PROTECTION PrintKernel("Info: Final memory health check...\n"); GetDetailedMemoryStats(&stats); if (stats.fragmentation_score > 50) { PrintKernelWarning("[WARN] High memory fragmentation detected\n"); } - - // Unmask IRQs - IRQUnmaskCoreSystems(); - // Memory protection StackGuardInit(); SetupMemoryProtection(); +#endif + // Unmask IRQs + IRQUnmaskCoreSystems(); return INIT_SUCCESS; } diff --git a/meson.build b/meson.build index 94e31de..5a11c44 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,7 @@ inc_dirs = [ src_root + '/drivers/xHCI', src_root + '/drivers/ISA', src_root + '/drivers/sound', + src_root + '/drivers/virtio', src_root + '/fs', src_root + '/mm', src_root + '/mm/trace', @@ -122,6 +123,7 @@ c_sources = [ src_root + '/drivers/LPT/LPT.c', src_root + '/drivers/APIC.c', src_root + '/drivers/InterruptController.c', + src_root + '/drivers/virtio/VirtioBlk.c', arch_root + '/idt/Idt.c', arch_root + '/gdt/Gdt.c', arch_root + '/interrupts/Interrupts.c', @@ -135,12 +137,21 @@ obj_sources = [ vf_config_flags = [ '-DVF_CONFIG_ENABLE_XHCI', + '-DVF_CONFIG_ENABLE_VIRTIO', + '-DVF_CONFIG_ENABLE_ISA', + '-DVF_CONFIG_ENABLE_LPT', + '-DVF_CONFIG_ENABLE_PCI', + '-DVF_CONFIG_ENABLE_PS2', + '-DVF_CONFIG_ENABLE_INITRD', + '-DVF_CONFIG_ENABLE_IDE', + '-DVF_CONFIG_ENFORCE_MEMORY_PROTECTION', '-DVF_CONFIG_VM_HOST', + '-DVF_CONFIG_MLFQ_SCHED', '-DVF_CONFIG_PROCINFO_CREATE_DEFAULT', '-DVF_CONFIG_USE_VFSHELL', '-DVF_CONFIG_USE_DYNAMOX', '-DVF_CONFIG_USE_ASTRA', - '-DVF_CONFIG_USE_CERBERUS', +# '-DVF_CONFIG_USE_CERBERUS', - breaks # '-DVF_CONFIG_PANIC_OVERRIDE', ] @@ -225,6 +236,8 @@ run_target('run', '-audio', 'pa,id=myaudio', '-device', 'sb16,iobase=0x220,irq=5,dma=5', '-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', ] ) @@ -235,3 +248,10 @@ run_target('img', mkfs_fat.full_path() + ' -F 12 VoidFrameDisk.img' ] ) + +run_target('virtio-img', + command: ['sh', '-c', + qemu_img.full_path() + ' create -f raw VirtioDisk.img 128M' + ' && ' + + mkfs_fat.full_path() + ' -F 12 VirtioDisk.img' + ] +) From a909af27dab508d1f1305b322702726a5fdf140a Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 1 Sep 2025 15:22:43 +0700 Subject: [PATCH 2/4] VirtIO --- README.md | 1 + docs/ARCHITECTURE.md | 26 +++++++++----- drivers/virtio/Virtio.h | 2 +- drivers/virtio/VirtioBlk.c | 72 ++++++++++++++++++++++---------------- kernel/etc/Shell.c | 6 ++++ kernel/process/Process.c | 1 + meson.build | 6 ++-- mm/security/Cerberus.c | 46 ++++++++++++++++++++---- mm/security/Cerberus.h | 2 ++ mm/trace/StackTrace.c | 2 +- 10 files changed, 114 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index b692d1b..5ca32e5 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ meson setup build cd build ninja ninja img # Optional +ninja virtio-img # Optional ninja run ``` diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 315bc71..f430cee 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -411,15 +411,23 @@ The following functions and commands provide interfaces to the process managemen - The kernel build options and flags are as follow (modify as needed) ```jetbrainsmeson vf_config_flags = [ - '-DVF_CONFIG_ENABLE_XHCI', # Enable xHCI driver - '-DVF_CONFIG_VM_HOST', # Enable support VM host (aka still run with failing features chekcs) - '-DVF_CONFIG_PROCINFO_CREATE_DEFAULT', # Create /Runtime/Processes/ by default - '-DVF_CONFIG_USE_VFSHELL', # Enable VFShell - '-DVF_CONFIG_USE_DYNAMOX', # Enable DynamoX - '-DVF_CONFIG_USE_ASTRA', # Enable Astra - '-DVF_CONFIG_USE_CERBERUS', # Enable Cerberus (memory protection) - '-DVF_CONFIG_PANIC_OVERRIDE', # Ignore many panics (sometimes it gets quite annoying) + '-DVF_CONFIG_ENABLE_XHCI', + '-DVF_CONFIG_ENABLE_VIRTIO', + '-DVF_CONFIG_ENABLE_ISA', + '-DVF_CONFIG_ENABLE_LPT', + '-DVF_CONFIG_ENABLE_PCI', + '-DVF_CONFIG_ENABLE_PS2', + '-DVF_CONFIG_ENABLE_INITRD', + '-DVF_CONFIG_ENABLE_IDE', + '-DVF_CONFIG_ENFORCE_MEMORY_PROTECTION', + '-DVF_CONFIG_VM_HOST', + '-DVF_CONFIG_MLFQ_SCHED', + '-DVF_CONFIG_PROCINFO_CREATE_DEFAULT', + '-DVF_CONFIG_USE_VFSHELL', + '-DVF_CONFIG_USE_DYNAMOX', + '-DVF_CONFIG_USE_ASTRA', + # '-DVF_CONFIG_USE_CERBERUS', + # '-DVF_CONFIG_PANIC_OVERRIDE', ] ``` - Quite simple, isn't it? > assembler-0 @ voidframe-kernel - 11:54 01/09/2025 \ No newline at end of file diff --git a/drivers/virtio/Virtio.h b/drivers/virtio/Virtio.h index 421c540..c905d60 100644 --- a/drivers/virtio/Virtio.h +++ b/drivers/virtio/Virtio.h @@ -72,7 +72,7 @@ struct VirtqDesc { struct VirtqAvail { uint16_t flags; - uint32_t idx; // Where the driver puts the next descriptor index (u32 for atomics) + uint16_t idx; uint16_t ring[]; // Array of descriptor indices } __attribute__((packed)); diff --git a/drivers/virtio/VirtioBlk.c b/drivers/virtio/VirtioBlk.c index 61a7904..3dece30 100644 --- a/drivers/virtio/VirtioBlk.c +++ b/drivers/virtio/VirtioBlk.c @@ -1,5 +1,5 @@ #include "VirtioBlk.h" - +#include "Spinlock.h" #include "Atomics.h" #include "Console.h" #include "PCI/PCI.h" @@ -7,6 +7,7 @@ #include "stdbool.h" // Globals to hold the capability structures we find +static volatile int* virtio_lock; static struct VirtioPciCap cap_common_cfg; static struct VirtioPciCap cap_notify_cfg; static struct VirtioPciCap cap_isr_cfg; @@ -168,7 +169,14 @@ void InitializeVirtioBlk(PciDevice device) { if (!vq_desc_table || !vq_avail_ring || !vq_used_ring) { PrintKernel("VirtIO-Blk: Error - Failed to allocate memory for virtqueue.\n"); - // TODO: Free allocated memory before returning + if (vq_desc_table) + VMemFree(vq_desc_table, sizeof(struct VirtqDesc) * vq_size); + if (vq_avail_ring) + VMemFree(vq_avail_ring, + sizeof(struct VirtqAvail) + sizeof(uint16_t) * vq_size); + if (vq_used_ring) + VMemFree(vq_used_ring, + sizeof(struct VirtqUsed) + sizeof(struct VirtqUsedElem) * vq_size); return; } @@ -184,59 +192,61 @@ void InitializeVirtioBlk(PciDevice device) { } int VirtioBlkRead(uint64_t sector, void* buffer) { + // Add synchronization for concurrent access + SpinLock(virtio_lock); + // Check if we have enough descriptors available + if ((vq_next_desc_idx + 3) > vq_size) { + PrintKernel("VirtIO-Blk: Error - Not enough descriptors available\n"); + // SpinUnlock(&virtio_lock); + return -1; + } // Step 1: Allocate request header and status byte struct VirtioBlkReq* req_hdr = VMemAlloc(sizeof(struct VirtioBlkReq)); uint8_t* status = VMemAlloc(sizeof(uint8_t)); if (!req_hdr || !status) { PrintKernel("VirtIO-Blk: Failed to allocate request header/status\n"); + if (req_hdr) VMemFree(req_hdr, sizeof(struct VirtioBlkReq)); + if (status) VMemFree(status, sizeof(uint8_t)); + // SpinUnlock(&virtio_lock); return -1; // Error } - // Step 2: Fill out the request header - req_hdr->type = VIRTIO_BLK_T_IN; + req_hdr->type = VIRTIO_BLK_T_IN; req_hdr->reserved = 0; - req_hdr->sector = sector; - + req_hdr->sector = sector; // Step 3: Set up the descriptor chain uint16_t head_idx = vq_next_desc_idx; - // Descriptor 1: Request Header (Driver -> Device) - vq_desc_table[head_idx].addr = VIRT_TO_PHYS((uint64_t)req_hdr); - vq_desc_table[head_idx].len = sizeof(struct VirtioBlkReq); + vq_desc_table[head_idx].addr = VIRT_TO_PHYS((uint64_t)req_hdr); + vq_desc_table[head_idx].len = sizeof(struct VirtioBlkReq); vq_desc_table[head_idx].flags = VIRTQ_DESC_F_NEXT; - vq_desc_table[head_idx].next = head_idx + 1; - + vq_desc_table[head_idx].next = head_idx + 1; // Descriptor 2: Data Buffer (Device -> Driver) - vq_desc_table[head_idx + 1].addr = VIRT_TO_PHYS((uint64_t)buffer); - vq_desc_table[head_idx + 1].len = 512; // Assume 512-byte sectors + vq_desc_table[head_idx + 1].addr = VIRT_TO_PHYS((uint64_t)buffer); + vq_desc_table[head_idx + 1].len = 512; // Assume 512-byte sectors vq_desc_table[head_idx + 1].flags = VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_NEXT; - vq_desc_table[head_idx + 1].next = head_idx + 2; - + vq_desc_table[head_idx + 1].next = head_idx + 2; // Descriptor 3: Status (Device -> Driver) - vq_desc_table[head_idx + 2].addr = VIRT_TO_PHYS((uint64_t)status); - vq_desc_table[head_idx + 2].len = sizeof(uint8_t); + vq_desc_table[head_idx + 2].addr = VIRT_TO_PHYS((uint64_t)status); + vq_desc_table[head_idx + 2].len = sizeof(uint8_t); vq_desc_table[head_idx + 2].flags = VIRTQ_DESC_F_WRITE; - vq_desc_table[head_idx + 2].next = 0; // End of chain - + vq_desc_table[head_idx + 2].next = 0; // End of chain // Step 4: Add the chain to the available ring vq_avail_ring->ring[vq_avail_ring->idx % vq_size] = head_idx; - // Step 5: Update the available ring index atomically - AtomicInc((volatile uint32_t*)&vq_avail_ring->idx); - + AtomicInc(&vq_avail_ring->idx); // Step 6: Notify the device if (notify_ptr) { *(notify_ptr + common_cfg_ptr->queue_notify_off) = 0; // Queue index is 0 } - // For now, we just update our internal descriptor index vq_next_desc_idx = (vq_next_desc_idx + 3) % vq_size; - - // TODO: Add interrupt handling to wait for the read to complete - // and check the status byte. - - // VMemFree(req_hdr, sizeof(struct VirtioBlkReq)); - // VMemFree(status, sizeof(uint8_t)); - + // TODO: Implement proper completion waiting mechanism + // This is critical for correctness + // For now, add a delay to allow completion (not production-ready) + // In production, use interrupts or polling with timeout + // Don't free these until after checking completion! + // These will need to be tracked and freed after the I/O completes + SpinUnlock(virtio_lock); return 0; // Success (for now) -} +} \ No newline at end of file diff --git a/kernel/etc/Shell.c b/kernel/etc/Shell.c index 904b421..929000a 100644 --- a/kernel/etc/Shell.c +++ b/kernel/etc/Shell.c @@ -1,6 +1,8 @@ #include "Shell.h" + #include "../../mm/KernelHeap.h" #include "../../mm/PMem.h" +#include "Cerberus.h" #include "Console.h" #include "ELFloader.h" #include "Editor.h" @@ -135,6 +137,7 @@ static void ClearHandler(const char * args) { static void ARPTestHandler(const char * args) { (void)args; + CreateProcess(ArpRequestTestProcess); } @@ -221,6 +224,7 @@ static void MemstatHandler(const char * args) { static void LsPCIHandler(const char * args) { (void)args; + CreateProcess(PciEnumerate); } @@ -262,6 +266,8 @@ static void PanicHandler(const char * args) { } static void LsUSBHandler(const char * args) { + (void)args; + CreateProcess(xHCIEnumerate); } diff --git a/kernel/process/Process.c b/kernel/process/Process.c index 1e9a546..1de9202 100644 --- a/kernel/process/Process.c +++ b/kernel/process/Process.c @@ -1073,6 +1073,7 @@ static __attribute__((visibility("hidden"))) uint32_t CreateSecureProcess(void ( processes[slot].preemption_count = 0; processes[slot].wait_time = 0; processes[slot].ProcessRuntimePath = FormatS("%s/%d", RuntimeProcesses, new_pid); + #ifdef VF_CONFIG_USE_CERBERUS CerberusRegisterProcess(new_pid, (uint64_t)stack, STACK_SIZE); #endif diff --git a/meson.build b/meson.build index 5a11c44..0d275dc 100644 --- a/meson.build +++ b/meson.build @@ -151,7 +151,9 @@ vf_config_flags = [ '-DVF_CONFIG_USE_VFSHELL', '-DVF_CONFIG_USE_DYNAMOX', '-DVF_CONFIG_USE_ASTRA', -# '-DVF_CONFIG_USE_CERBERUS', - breaks + '-DVF_CONFIG_USE_CERBERUS', +# '-DVF_CONFIG_CERBERUS_VFS_LOGGING', +# '-DVF_CONFIG_CERBERUS_THREAT_REPORTING', # '-DVF_CONFIG_PANIC_OVERRIDE', ] @@ -252,6 +254,6 @@ run_target('img', run_target('virtio-img', command: ['sh', '-c', qemu_img.full_path() + ' create -f raw VirtioDisk.img 128M' + ' && ' + - mkfs_fat.full_path() + ' -F 12 VirtioDisk.img' + mkfs_fat.full_path() + ' -F 16 VirtioDisk.img' ] ) diff --git a/mm/security/Cerberus.c b/mm/security/Cerberus.c index a993fc1..3bca9e5 100644 --- a/mm/security/Cerberus.c +++ b/mm/security/Cerberus.c @@ -11,6 +11,29 @@ static CerberusState g_cerberus_state = {0}; static volatile int cerberus_lock = 0; static uint64_t system_ticks = 0; +typedef struct { + uint64_t base_addr; + uint64_t end_addr; + const char* description; +} HardwareAccessRange; + +static HardwareAccessRange hardware_ranges[] = { + {0xCF8, 0xCFF, "PCI Configuration"}, + {0x80, 0x8F, "DMA Controller"}, + {0xA0, 0xBF, "PIC Controller"}, + // Add more hardware ranges as needed +}; + +static bool IsLegitimateHardwareAccess(uint64_t fault_addr) { + for (int i = 0; i < sizeof(hardware_ranges)/sizeof(hardware_ranges[0]); i++) { + if (fault_addr >= hardware_ranges[i].base_addr && + fault_addr <= hardware_ranges[i].end_addr) { + return true; + } + } + return false; +} + void CerberusLogViolation(CerberusViolationReport* report) { if (!g_cerberus_state.is_initialized || !report) return; @@ -28,7 +51,7 @@ void CerberusLogViolation(CerberusViolationReport* report) { // Console logging PrintKernelErrorF("[Cerberus] VIOLATION PID=%d: %s\n", report->process_id, report->description); - +#ifdef VF_CONFIG_CERBERUS_VFS_LOGGING // VFS logging char log_entry[256]; FormatA(log_entry, sizeof(log_entry), @@ -37,6 +60,8 @@ void CerberusLogViolation(CerberusViolationReport* report) { report->fault_address, report->rip, report->description); VfsAppendFile("/ProcINFO/Cerberus/violations.log", log_entry, StringLength(log_entry)); +#endif + } void CerberusInit(void) { @@ -57,12 +82,12 @@ void CerberusInit(void) { g_cerberus_state.monitored_processes = 0; g_cerberus_state.total_violations = 0; g_cerberus_state.is_initialized = true; - +#ifdef VF_CONFIG_CERBERUS_VFS_LOGGING // Create logging directories in VFS VfsCreateDir(FormatS("%s/Cerberus", RuntimeServices)); VfsCreateFile(FormatS("%s/Cerberus/violations.log", RuntimeServices)); VfsCreateFile(FormatS("%s/Cerberus/watchlist.log", RuntimeServices)); - +#endif PrintKernelSuccess("Cerberus initialized\n"); } @@ -87,9 +112,9 @@ int CerberusRegisterProcess(uint32_t pid, uint64_t stack_base, uint64_t stack_si proc_info->last_violation = 0; // Install stack protection if stack provided - if (stack_base && stack_size > 16) { - CerberusInstallStackCanary(pid, stack_base, stack_size); - } + // if (stack_base && stack_size > 16) { + // CerberusInstallStackCanary(pid, stack_base, stack_size); + // } g_cerberus_state.monitored_processes++; SpinUnlock(&cerberus_lock); @@ -188,20 +213,26 @@ void CerberusPreScheduleCheck(uint32_t pid) { // Block compromised processes if (proc_info->is_compromised) { PrintKernelErrorF("[Cerberus] BLOCKED compromised process %d\n", pid); +#ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING CerberusReportThreat(pid, MEM_VIOLATION_STACK_CORRUPTION); +#endif return; } // Check stack canary if (CerberusCheckStackCanary(pid) != 0) { PrintKernelErrorF("[Cerberus] Stack canary violation in PID %d\n", pid); +#ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING CerberusReportThreat(pid, MEM_VIOLATION_CANARY_CORRUPT); +#endif } // Check violation threshold if (proc_info->violation_count >= CERBERUS_VIOLATION_THRESHOLD) { PrintKernelWarningF("[Cerberus] PID %d exceeded violation threshold\n", pid); +#ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING CerberusReportThreat(pid, MEM_VIOLATION_BOUNDS_CHECK); +#endif } } @@ -231,6 +262,7 @@ void CerberusTick(void) { int CerberusAnalyzeFault(uint64_t fault_addr, uint64_t error_code, uint32_t pid, uint64_t rip) { if (!g_cerberus_state.is_initialized) return 0; + if (IsLegitimateHardwareAccess(fault_addr)) return 0; MemorySecurityViolation violation_type = MEM_VIOLATION_NONE; @@ -264,6 +296,7 @@ int CerberusAnalyzeFault(uint64_t fault_addr, uint64_t error_code, uint32_t pid, return 0; // No violation } +#ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING void CerberusReportThreat(uint32_t pid, MemorySecurityViolation violation) { if (!g_cerberus_state.is_initialized) return; @@ -279,6 +312,7 @@ void CerberusReportThreat(uint32_t pid, MemorySecurityViolation violation) { PrintKernelWarningF("[Cerberus] Threat reported to Astra: PID=%d\n", pid); } +#endif int CerberusTrackAlloc(uint64_t addr, uint64_t size, uint32_t pid) { if (!g_cerberus_state.is_initialized) return -1; diff --git a/mm/security/Cerberus.h b/mm/security/Cerberus.h index c4e75cc..3aac73c 100644 --- a/mm/security/Cerberus.h +++ b/mm/security/Cerberus.h @@ -66,7 +66,9 @@ void CerberusUnregisterProcess(uint32_t pid); void CerberusPreScheduleCheck(uint32_t pid); void CerberusTick(void); int CerberusAnalyzeFault(uint64_t fault_addr, uint64_t error_code, uint32_t pid, uint64_t rip); +#ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING void CerberusReportThreat(uint32_t pid, MemorySecurityViolation violation); +#endif void CerberusDumpStats(void); // Memory tracking diff --git a/mm/trace/StackTrace.c b/mm/trace/StackTrace.c index 7891499..54aa795 100644 --- a/mm/trace/StackTrace.c +++ b/mm/trace/StackTrace.c @@ -62,7 +62,7 @@ int WalkStack(uint64_t rbp, uint64_t rip, StackFrame* frames, int max_frames) { void AnalyzePageFault(uint64_t cr2, uint64_t error_code, FaultContext* ctx) { ctx->fault_address = cr2; - + // Decode page fault error code bits bool present = (error_code & 0x1) != 0; bool write = (error_code & 0x2) != 0; From 8caaccb45c14eb38c6800a1dbb62ec34130197d4 Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 1 Sep 2025 16:23:53 +0700 Subject: [PATCH 3/4] New script --- .gitignore | 3 +- arch/x86_64/idt/Idt.c | 6 +- meson.build | 4 +- vfconfig.py | 376 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 382 insertions(+), 7 deletions(-) create mode 100755 vfconfig.py diff --git a/.gitignore b/.gitignore index 5a5a644..3a35b28 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ Meson-Build Makefile CMakeLists.txt *build* -target \ No newline at end of file +target +.venv \ No newline at end of file diff --git a/arch/x86_64/idt/Idt.c b/arch/x86_64/idt/Idt.c index ea1d390..8ee3bed 100644 --- a/arch/x86_64/idt/Idt.c +++ b/arch/x86_64/idt/Idt.c @@ -1,6 +1,4 @@ #include "Idt.h" - -#include "Console.h" #include "Kernel.h" #define IDT_ENTRIES 256 @@ -90,7 +88,7 @@ extern void isr76(); extern void isr77(); extern void isr78(); extern void isr79(); -// extern void isr80(); +extern void isr80(); extern void isr81(); extern void isr82(); extern void isr83(); @@ -366,7 +364,7 @@ int IdtInstall() { IdtSetGate(77, (uint64_t)isr77, kernelCodeSegment, flags); IdtSetGate(78, (uint64_t)isr78, kernelCodeSegment, flags); IdtSetGate(79, (uint64_t)isr79, kernelCodeSegment, flags); - // IdtSetGate(80, (uint64_t)isr80, kernelCodeSegment, flags); + IdtSetGate(80, (uint64_t)isr80, kernelCodeSegment, flags); IdtSetGate(81, (uint64_t)isr81, kernelCodeSegment, flags); IdtSetGate(82, (uint64_t)isr82, kernelCodeSegment, flags); IdtSetGate(83, (uint64_t)isr83, kernelCodeSegment, flags); diff --git a/meson.build b/meson.build index 0d275dc..2664043 100644 --- a/meson.build +++ b/meson.build @@ -152,8 +152,8 @@ vf_config_flags = [ '-DVF_CONFIG_USE_DYNAMOX', '-DVF_CONFIG_USE_ASTRA', '-DVF_CONFIG_USE_CERBERUS', -# '-DVF_CONFIG_CERBERUS_VFS_LOGGING', -# '-DVF_CONFIG_CERBERUS_THREAT_REPORTING', + '-DVF_CONFIG_CERBERUS_VFS_LOGGING', + '-DVF_CONFIG_CERBERUS_THREAT_REPORTING', # '-DVF_CONFIG_PANIC_OVERRIDE', ] diff --git a/vfconfig.py b/vfconfig.py new file mode 100755 index 0000000..ebb7270 --- /dev/null +++ b/vfconfig.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 +""" +Meson Config Flag Editor - A TUI for managing kernel config flags in meson.build +""" + +import re +import os +import sys +from typing import List, Tuple, Optional +from dataclasses import dataclass +from textual.app import App, ComposeResult +from textual.containers import Horizontal, Vertical, ScrollableContainer +from textual.widgets import Header, Footer, Static, Checkbox, Button, Label +from textual.binding import Binding +from textual.screen import ModalScreen +from textual.widgets import Input +from textual import on +from textual.message import Message + +@dataclass +class ConfigFlag: + name: str + enabled: bool + description: str = "" + line_number: int = 0 + +class SaveConfirmScreen(ModalScreen[bool]): + """Modal screen for confirming save operation.""" + + BINDINGS = [ + ("y", "confirm", "Yes"), + ("n", "cancel", "No"), + ("escape", "cancel", "Cancel"), + ] + + def compose(self) -> ComposeResult: + yield Vertical( + Static("Save changes to meson.build?", classes="question"), + Horizontal( + Button("Yes", variant="success", id="yes"), + Button("No", variant="error", id="no"), + classes="buttons", + ), + classes="dialog", + ) + + def on_button_pressed(self, event: Button.Pressed) -> None: + if event.button.id == "yes": + self.dismiss(True) + else: + self.dismiss(False) + + def action_confirm(self) -> None: + self.dismiss(True) + + def action_cancel(self) -> None: + self.dismiss(False) + +class ConfigFlagWidget(Static): + """Widget representing a single config flag with checkbox and description.""" + + def __init__(self, flag: ConfigFlag, **kwargs): + super().__init__(**kwargs) + self.flag = flag + + def compose(self) -> ComposeResult: + with Horizontal(): + checkbox = Checkbox(self.flag.name, self.flag.enabled, id=f"check_{self.flag.name}") + yield checkbox + if self.flag.description: + yield Label(f"- {self.flag.description}", classes="flag-desc") + + @on(Checkbox.Changed) + def on_checkbox_changed(self, event: Checkbox.Changed) -> None: + self.flag.enabled = event.value + # Send message to parent about the change + self.post_message(ConfigFlagChanged(self.flag)) + +class ConfigFlagChanged(Message): + """Message sent when a config flag is toggled.""" + + def __init__(self, flag: ConfigFlag): + self.flag = flag + super().__init__() + +class MesonConfigEditor(App): + """Main application for editing meson config flags.""" + + CSS = """ + .dialog { + align: center middle; + background: $surface; + border: thick $primary; + width: 50%; + height: auto; + padding: 1; + } + + .question { + text-align: center; + margin: 1; + } + + .buttons { + align: center middle; + height: auto; + } + + .flag-name { + min-width: 40; + color: $accent; + } + + .flag-desc { + color: $text-muted; + text-style: italic; + } + + .stats { + background: $panel; + padding: 1; + margin: 1; + } + + .container { + padding: 1; + } + """ + + BINDINGS = [ + ("q", "quit", "Quit"), + ("s", "save", "Save"), + ("r", "reload", "Reload"), + ("a", "toggle_all", "Toggle All"), + ("?", "help", "Help"), + ] + + def __init__(self, filename: str = "meson.build"): + super().__init__() + self.filename = filename + self.flags: List[ConfigFlag] = [] + self.original_content: str = "" + self.flag_widgets: List[ConfigFlagWidget] = [] + + def compose(self) -> ComposeResult: + yield Header() + with Vertical(): + yield Static(f"Editing: {self.filename}", classes="stats") + with ScrollableContainer(classes="container", id="flag_container"): + yield Static("Loading...") + yield Footer() + + def on_mount(self) -> None: + """Load the meson.build file when the app starts.""" + self.load_file() + + def load_file(self) -> None: + """Load and parse the meson.build file.""" + try: + with open(self.filename, 'r') as f: + self.original_content = f.read() + + self.flags = self.parse_config_flags(self.original_content) + self.update_display() + + except FileNotFoundError: + self.notify(f"Error: {self.filename} not found!", severity="error") + except Exception as e: + self.notify(f"Error loading file: {e}", severity="error") + + + def parse_config_flags(self, content: str) -> List[ConfigFlag]: + """Parse config flags from meson.build content.""" + flags = [] + lines = content.split('\n') + + # Look for vf_config_flags array + in_config_array = False + array_pattern = r'vf_config_flags\s*=\s*\[' + + for i, line in enumerate(lines): + if re.search(array_pattern, line): + in_config_array = True + continue + + if in_config_array: + if ']' in line: + break + + # More flexible pattern to handle various formats + # Handle both commented and uncommented lines + stripped_line = line.strip() + if not stripped_line or stripped_line.startswith('//'): + continue + + # Check if line contains a flag + if "'" in stripped_line: + # Extract flag content between quotes + start_quote = stripped_line.find("'") + end_quote = stripped_line.find("'", start_quote + 1) + + if start_quote != -1 and end_quote != -1: + flag_full = stripped_line[start_quote + 1:end_quote] + + # Check if line is commented + is_commented = stripped_line.startswith('#') + + # Extract description (everything after # at the end) + description = "" + comment_pos = stripped_line.find('#', end_quote) + if comment_pos != -1: + description = stripped_line[comment_pos + 1:].strip() + + # Extract flag name (remove -D prefix if present) + flag_name = flag_full + if flag_name.startswith('-D'): + flag_name = flag_name[2:] + + flags.append(ConfigFlag( + name=flag_name, + enabled=not is_commented, + description=description, + line_number=i + )) + + return flags + + + def update_display(self) -> None: + """Update the display with current flags.""" + container = self.query_one("#flag_container") + + # Clear existing content + container.remove_children() + self.flag_widgets.clear() + + if not self.flags: + container.mount(Static("No config flags found in vf_config_flags array")) + return + + # Add statistics + enabled_count = sum(1 for f in self.flags if f.enabled) + stats_text = f"Total flags: {len(self.flags)} | Enabled: {enabled_count} | Disabled: {len(self.flags) - enabled_count}" + + # Create and mount stats widget + stats_widget = Static(stats_text, classes="stats", id="stats_display") + container.mount(stats_widget) + + # Add flag widgets + for flag in self.flags: + widget = ConfigFlagWidget(flag) + self.flag_widgets.append(widget) + container.mount(widget) + + # Debug: Add a message about how many flags were found + self.notify(f"Loaded {len(self.flags)} flags", severity="information") + + @on(ConfigFlagChanged) + def on_config_flag_changed(self, message: ConfigFlagChanged) -> None: + """Handle when a config flag is toggled.""" + enabled_count = sum(1 for f in self.flags if f.enabled) + stats_text = f"Total flags: {len(self.flags)} | Enabled: {enabled_count} | Disabled: {len(self.flags) - enabled_count}" + + # Update stats display + stats_widget = self.query(".stats").first() + if stats_widget and hasattr(stats_widget, 'update'): + stats_widget.update(stats_text) + + def action_save(self) -> None: + """Save changes to the file.""" + async def _save(): + if await self.push_screen_wait(SaveConfirmScreen()): + try: + new_content = self.generate_updated_content() + with open(self.filename, 'w') as f: + f.write(new_content) + self.notify("File saved successfully!", severity="information") + except Exception as e: + self.notify(f"Error saving file: {e}", severity="error") + + self.run_worker(_save()) + + def generate_updated_content(self) -> str: + """Generate updated file content with current flag states.""" + lines = self.original_content.split('\n') + + # Create a mapping of line numbers to flags + line_to_flag = {flag.line_number: flag for flag in self.flags} + + for line_num, flag in line_to_flag.items(): + if line_num < len(lines): + line = lines[line_num] + + # Parse the current line + flag_pattern = r'^\s*(#?)\s*(\'[^\']+\',?)\s*(#.*)?$' + match = re.match(flag_pattern, line) + + if match: + current_comment = match.group(1) or "" + flag_part = match.group(2) + desc_comment = match.group(3) or "" + + # Update based on flag state + if flag.enabled: + # Remove comment if present + new_line = f" {flag_part}" + else: + # Add comment if not present + new_line = f"# {flag_part}" + + # Preserve description comment + if desc_comment: + new_line += f" {desc_comment}" + + lines[line_num] = new_line + + return '\n'.join(lines) + + def action_reload(self) -> None: + """Reload the file from disk.""" + self.load_file() + self.notify("File reloaded", severity="information") + + def action_toggle_all(self) -> None: + """Toggle all flags on or off.""" + if not self.flags: + return + + # Determine if we should enable all or disable all + enabled_count = sum(1 for f in self.flags if f.enabled) + should_enable = enabled_count < len(self.flags) / 2 + + # Update all flags + for flag in self.flags: + flag.enabled = should_enable + + # Update all checkboxes + for widget in self.flag_widgets: + checkbox = widget.query_one(Checkbox) + checkbox.value = should_enable + + self.update_display() + action = "enabled" if should_enable else "disabled" + self.notify(f"All flags {action}", severity="information") + + def action_help(self) -> None: + """Show help information.""" + help_text = """ +Meson Config Flag Editor + +Keyboard Shortcuts: +- s: Save changes +- r: Reload file +- a: Toggle all flags +- q: Quit +- Space: Toggle selected flag + +Use mouse or arrow keys to navigate. +Check/uncheck boxes to enable/disable flags. + """ + self.notify(help_text.strip(), severity="information") + +def main(): + """Main entry point.""" + filename = sys.argv[1] if len(sys.argv) > 1 else "meson.build" + + if not os.path.exists(filename): + print(f"Error: {filename} not found!") + print("Usage: python meson_config_editor.py [meson.build]") + sys.exit(1) + + app = MesonConfigEditor(filename) + app.run() + +if __name__ == "__main__": + main() \ No newline at end of file From ac5d3f8c088e20754cd8bc4d77ef039bc8b9d5db Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 1 Sep 2025 16:57:43 +0700 Subject: [PATCH 4/4] New script --- mm/security/Cerberus.c | 24 ----- vfconfig.py | 196 ++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 144 deletions(-) diff --git a/mm/security/Cerberus.c b/mm/security/Cerberus.c index 3bca9e5..ac1bce3 100644 --- a/mm/security/Cerberus.c +++ b/mm/security/Cerberus.c @@ -11,29 +11,6 @@ static CerberusState g_cerberus_state = {0}; static volatile int cerberus_lock = 0; static uint64_t system_ticks = 0; -typedef struct { - uint64_t base_addr; - uint64_t end_addr; - const char* description; -} HardwareAccessRange; - -static HardwareAccessRange hardware_ranges[] = { - {0xCF8, 0xCFF, "PCI Configuration"}, - {0x80, 0x8F, "DMA Controller"}, - {0xA0, 0xBF, "PIC Controller"}, - // Add more hardware ranges as needed -}; - -static bool IsLegitimateHardwareAccess(uint64_t fault_addr) { - for (int i = 0; i < sizeof(hardware_ranges)/sizeof(hardware_ranges[0]); i++) { - if (fault_addr >= hardware_ranges[i].base_addr && - fault_addr <= hardware_ranges[i].end_addr) { - return true; - } - } - return false; -} - void CerberusLogViolation(CerberusViolationReport* report) { if (!g_cerberus_state.is_initialized || !report) return; @@ -262,7 +239,6 @@ void CerberusTick(void) { int CerberusAnalyzeFault(uint64_t fault_addr, uint64_t error_code, uint32_t pid, uint64_t rip) { if (!g_cerberus_state.is_initialized) return 0; - if (IsLegitimateHardwareAccess(fault_addr)) return 0; MemorySecurityViolation violation_type = MEM_VIOLATION_NONE; diff --git a/vfconfig.py b/vfconfig.py index ebb7270..def27d8 100755 --- a/vfconfig.py +++ b/vfconfig.py @@ -23,6 +23,7 @@ class ConfigFlag: enabled: bool description: str = "" line_number: int = 0 + original_line: str = "" class SaveConfirmScreen(ModalScreen[bool]): """Modal screen for confirming save operation.""" @@ -73,7 +74,6 @@ def compose(self) -> ComposeResult: @on(Checkbox.Changed) def on_checkbox_changed(self, event: Checkbox.Changed) -> None: self.flag.enabled = event.value - # Send message to parent about the change self.post_message(ConfigFlagChanged(self.flag)) class ConfigFlagChanged(Message): @@ -116,10 +116,15 @@ class MesonConfigEditor(App): text-style: italic; } - .stats { + /* This was the cause of the spacing issue. It has been removed. */ + /* .flag-container { + height: 1; + } */ + + #stats_display { background: $panel; padding: 1; - margin: 1; + margin-bottom: 1; } .container { @@ -139,209 +144,162 @@ def __init__(self, filename: str = "meson.build"): super().__init__() self.filename = filename self.flags: List[ConfigFlag] = [] - self.original_content: str = "" + self.original_content: List[str] = [] self.flag_widgets: List[ConfigFlagWidget] = [] def compose(self) -> ComposeResult: yield Header() - with Vertical(): - yield Static(f"Editing: {self.filename}", classes="stats") - with ScrollableContainer(classes="container", id="flag_container"): + with Vertical(classes="container"): + yield Static(f"Editing: {self.filename}") + yield Static(id="stats_display") + with ScrollableContainer(id="flag_container"): yield Static("Loading...") yield Footer() def on_mount(self) -> None: - """Load the meson.build file when the app starts.""" self.load_file() def load_file(self) -> None: - """Load and parse the meson.build file.""" try: with open(self.filename, 'r') as f: - self.original_content = f.read() - + self.original_content = f.readlines() self.flags = self.parse_config_flags(self.original_content) self.update_display() - except FileNotFoundError: self.notify(f"Error: {self.filename} not found!", severity="error") except Exception as e: self.notify(f"Error loading file: {e}", severity="error") - - def parse_config_flags(self, content: str) -> List[ConfigFlag]: - """Parse config flags from meson.build content.""" + def parse_config_flags(self, lines: List[str]) -> List[ConfigFlag]: + """Parse config flags from meson.build content using a robust regex.""" flags = [] - lines = content.split('\n') - - # Look for vf_config_flags array in_config_array = False array_pattern = r'vf_config_flags\s*=\s*\[' + # Regex to capture the flag line structure + # Group 1: Optional leading '#' + # Group 2: The flag name inside '-D' and quotes + # Group 3: Optional description comment + flag_pattern = re.compile(r"^\s*(#)?\s*'-D([^']+)'.*?(#\s*(.*))?$") for i, line in enumerate(lines): - if re.search(array_pattern, line): + line_content = line.strip() + if re.search(array_pattern, line_content): in_config_array = True continue - if in_config_array: - if ']' in line: + if ']' in line_content: break - # More flexible pattern to handle various formats - # Handle both commented and uncommented lines - stripped_line = line.strip() - if not stripped_line or stripped_line.startswith('//'): - continue - - # Check if line contains a flag - if "'" in stripped_line: - # Extract flag content between quotes - start_quote = stripped_line.find("'") - end_quote = stripped_line.find("'", start_quote + 1) - - if start_quote != -1 and end_quote != -1: - flag_full = stripped_line[start_quote + 1:end_quote] - - # Check if line is commented - is_commented = stripped_line.startswith('#') - - # Extract description (everything after # at the end) - description = "" - comment_pos = stripped_line.find('#', end_quote) - if comment_pos != -1: - description = stripped_line[comment_pos + 1:].strip() - - # Extract flag name (remove -D prefix if present) - flag_name = flag_full - if flag_name.startswith('-D'): - flag_name = flag_name[2:] - - flags.append(ConfigFlag( - name=flag_name, - enabled=not is_commented, - description=description, - line_number=i - )) - + match = flag_pattern.match(line_content) + if match: + is_commented = match.group(1) is not None + flag_name = match.group(2) + description = match.group(4).strip() if match.group(4) else "" + + flags.append(ConfigFlag( + name=flag_name, + enabled=not is_commented, + description=description, + line_number=i, + original_line=line + )) return flags - def update_display(self) -> None: """Update the display with current flags.""" container = self.query_one("#flag_container") - - # Clear existing content container.remove_children() self.flag_widgets.clear() if not self.flags: - container.mount(Static("No config flags found in vf_config_flags array")) + container.mount(Static("No config flags found in vf_config_flags array.")) return - # Add statistics - enabled_count = sum(1 for f in self.flags if f.enabled) - stats_text = f"Total flags: {len(self.flags)} | Enabled: {enabled_count} | Disabled: {len(self.flags) - enabled_count}" - - # Create and mount stats widget - stats_widget = Static(stats_text, classes="stats", id="stats_display") - container.mount(stats_widget) + self.update_stats() - # Add flag widgets for flag in self.flags: widget = ConfigFlagWidget(flag) self.flag_widgets.append(widget) container.mount(widget) + self.notify(f"Loaded {len(self.flags)} flags.") - # Debug: Add a message about how many flags were found - self.notify(f"Loaded {len(self.flags)} flags", severity="information") + def update_stats(self) -> None: + """Update the statistics display.""" + if not self.flags: + return + enabled_count = sum(1 for f in self.flags if f.enabled) + stats_text = f"Total: {len(self.flags)} | Enabled: {enabled_count} | Disabled: {len(self.flags) - enabled_count}" + self.query_one("#stats_display", Static).update(stats_text) @on(ConfigFlagChanged) def on_config_flag_changed(self, message: ConfigFlagChanged) -> None: - """Handle when a config flag is toggled.""" - enabled_count = sum(1 for f in self.flags if f.enabled) - stats_text = f"Total flags: {len(self.flags)} | Enabled: {enabled_count} | Disabled: {len(self.flags) - enabled_count}" - - # Update stats display - stats_widget = self.query(".stats").first() - if stats_widget and hasattr(stats_widget, 'update'): - stats_widget.update(stats_text) + """Handle when a config flag is toggled by updating stats.""" + self.update_stats() def action_save(self) -> None: """Save changes to the file.""" async def _save(): - if await self.push_screen_wait(SaveConfirmScreen()): + confirmed = await self.push_screen_wait(SaveConfirmScreen()) + if confirmed: try: new_content = self.generate_updated_content() with open(self.filename, 'w') as f: f.write(new_content) - self.notify("File saved successfully!", severity="information") + self.notify("File saved successfully!") + self.load_file() # Reload to confirm changes except Exception as e: self.notify(f"Error saving file: {e}", severity="error") - self.run_worker(_save()) def generate_updated_content(self) -> str: - """Generate updated file content with current flag states.""" - lines = self.original_content.split('\n') + """Generate updated file content by modifying lines based on flag state.""" + lines = list(self.original_content) # Make a copy - # Create a mapping of line numbers to flags - line_to_flag = {flag.line_number: flag for flag in self.flags} - - for line_num, flag in line_to_flag.items(): - if line_num < len(lines): - line = lines[line_num] - - # Parse the current line - flag_pattern = r'^\s*(#?)\s*(\'[^\']+\',?)\s*(#.*)?$' - match = re.match(flag_pattern, line) + for flag in self.flags: + line_num = flag.line_number + original_line = lines[line_num] + stripped_line = original_line.lstrip() - if match: - current_comment = match.group(1) or "" - flag_part = match.group(2) - desc_comment = match.group(3) or "" + is_currently_commented = stripped_line.startswith('#') - # Update based on flag state - if flag.enabled: - # Remove comment if present - new_line = f" {flag_part}" - else: - # Add comment if not present - new_line = f"# {flag_part}" + # Case 1: Flag should be enabled, but is currently commented + if flag.enabled and is_currently_commented: + # Find first '#' and remove it + lines[line_num] = original_line.replace('#', '', 1) - # Preserve description comment - if desc_comment: - new_line += f" {desc_comment}" + # Case 2: Flag should be disabled, but is currently not commented + elif not flag.enabled and not is_currently_commented: + indent_len = len(original_line) - len(stripped_line) + indent = ' ' * indent_len + # Add '#' right before the content starts + lines[line_num] = f"{indent}#{stripped_line}" - lines[line_num] = new_line + return "".join(lines) - return '\n'.join(lines) def action_reload(self) -> None: """Reload the file from disk.""" self.load_file() - self.notify("File reloaded", severity="information") + self.notify("File reloaded.") def action_toggle_all(self) -> None: """Toggle all flags on or off.""" if not self.flags: return - # Determine if we should enable all or disable all enabled_count = sum(1 for f in self.flags if f.enabled) should_enable = enabled_count < len(self.flags) / 2 - # Update all flags for flag in self.flags: flag.enabled = should_enable - # Update all checkboxes for widget in self.flag_widgets: checkbox = widget.query_one(Checkbox) checkbox.value = should_enable - self.update_display() + self.update_stats() action = "enabled" if should_enable else "disabled" - self.notify(f"All flags {action}", severity="information") + self.notify(f"All flags {action}.") def action_help(self) -> None: """Show help information.""" @@ -358,17 +316,15 @@ def action_help(self) -> None: Use mouse or arrow keys to navigate. Check/uncheck boxes to enable/disable flags. """ - self.notify(help_text.strip(), severity="information") + self.notify(help_text.strip()) def main(): """Main entry point.""" filename = sys.argv[1] if len(sys.argv) > 1 else "meson.build" - if not os.path.exists(filename): print(f"Error: {filename} not found!") - print("Usage: python meson_config_editor.py [meson.build]") + print("Usage: python vfconfig.py [path/to/meson.build]") sys.exit(1) - app = MesonConfigEditor(filename) app.run()