Skip to content

Conversation

assembler-0
Copy link
Owner

@assembler-0 assembler-0 commented Sep 1, 2025

Summary by CodeRabbit

  • New Features

    • VirtIO block storage support with automatic VirtIO device detection and a run target to create/use a VirtIO disk image.
    • New kernel build options and subsystems (PCI, ISA, PS/2, IDE, LPT, initrd, MLFQ, memory protection, threat reporting).
    • Terminal UI to edit Meson build config flags.
  • Bug Fixes / Known Issues

    • FAT12 directory creation path may leak memory (needs attention).
  • Chores

    • Build/run targets, flags, and startup diagnostics updated; .venv added to .gitignore.
  • Documentation

    • Quickstart and architecture docs updated to document virtio-img and expanded config flags.

Copy link

coderabbitai bot commented Sep 1, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds VirtIO PCI/block support (headers, driver, PCI handler), aligns PCI config byte reads, extends build/runtime targets and VF flags, restructures kernel init with many feature gates, alters FAT12 directory creation to remove a free (possible leak), and enhances Cerberus threat/logging behavior and gating.

Changes

Cohort / File(s) Summary
VirtIO driver & API
drivers/virtio/Virtio.h, drivers/virtio/VirtioBlk.h, drivers/virtio/VirtioBlk.c
New VirtIO definitions and VirtioBlk driver: PCI capability parsing, MMIO/BAR mapping, device init (reset/ACK/feature negotiation), virtqueue setup, and a read path (VirtioBlkRead). Exposes InitializeVirtioBlk and VirtioBlkRead.
PCI updates
drivers/PCI/PCI.c
Adds VirtIO PCI integration: includes Virtio.h, new internal PciVirtioHandler, conditional bus scan for virtio devices when enabled, wires InitializeVirtioBlk for known VirtIO IDs, and changes PciConfigReadByte to perform aligned 32-bit DWord reads and extract the requested byte.
Build & runtime targets
meson.build, README.md, docs/ARCHITECTURE.md
Adds /drivers/virtio include and drivers/virtio/VirtioBlk.c to sources, expands vf_config_flags with many VF_CONFIG_* entries (including VF_CONFIG_ENABLE_VIRTIO), updates QEMU run to attach a virtio-blk device, adds virtio-img target, and documents the optional target in README.
Kernel init / gating
kernel/core/Kernel.c
Reorders and expands bootstrap/init sequence; gates many subsystems (PCI/ISA/LPT/PS2/IDE/INITRD/MLFQ/etc.), moves memory-protection/enforcement behind VF_CONFIG_ENFORCE_MEMORY_PROTECTION, adds memory stats and bootstrap mapping diagnostics, and adjusts subsystem init ordering.
Cerberus security changes
mm/security/Cerberus.c, mm/security/Cerberus.h
Adds optional VFS-based violation logging and threat-reporting API (CerberusReportThreat) gated by config flags; disables automatic stack-canary installation on registration; adds double-free detection and wiring to report threats on violations. Declaration of CerberusReportThreat added to header (guarded by flag).
FAT12 allocation change
fs/FAT12.c
Removes a KernelFree(cluster_buffer) call in Fat12CreateDir (commented out as potential double free), leaving the buffer allocated and introducing a possible memory leak on the new-directory path.
TUI tool for VF flags
vfconfig.py
New textual Meson config editor: parses vf_config_flags, renders interactive toggles, supports save/reload, and writes updated meson.build while preserving comments/indentation.
Minor edits / formatting & misc
kernel/etc/Shell.c, kernel/process/Process.c, mm/trace/StackTrace.c, .gitignore, arch/x86_64/idt/Idt.c
Small formatting/unused-arg annotations, added .venv to .gitignore, enabled isr80 extern and wired IDT gate entry 80, and include adjustments; no behavioral changes except the IDT wiring noted.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Kernel
  participant PCI
  participant VirtioHandler as PciVirtioHandler
  participant VirtioBlk as VirtioBlk.Init
  participant Device as VirtIO_Device

  Kernel->>PCI: PciScanBus()
  PCI->>VirtioHandler: invoke per device
  VirtioHandler->>VirtioBlk: InitializeVirtioBlk(device)
  VirtioBlk->>Device: Read Virtio PCI caps, map BARs
  VirtioBlk->>Device: Enable MMIO/BusMaster, set STATUS RESET→ACK→DRIVER
  VirtioBlk->>Device: Feature negotiation → FEATURES_OK
  VirtioBlk->>Device: Configure virtqueue (desc/avail/used addresses)
  VirtioBlk-->>Kernel: Initialization complete / device ready
Loading
sequenceDiagram
  autonumber
  participant Caller as Block IO Caller
  participant VirtioBlk as VirtioBlkRead
  participant Queue as Virtqueue
  participant Device as VirtIO_Device

  Caller->>VirtioBlk: VirtioBlkRead(sector, buffer)
  VirtioBlk->>Queue: Allocate and populate 3 descriptors (hdr, data, status)
  VirtioBlk->>Queue: Enqueue (avail.ring), bump avail.idx
  VirtioBlk->>Device: Notify via notify BAR (if present)
  Device-->>Queue: Process request, update used ring & status
  VirtioBlk-->>Caller: Poll/observe completion and return status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Development #105 — Implements the same VirtIO PCI integration and adds drivers/virtio/* and meson changes (highly related).
  • Development #68 — Overlaps edits to drivers/PCI/PCI.c (PCI enumeration and virtio wiring).
  • Development #98 — Related edits to fs/FAT12.c, specifically the Fat12CreateDir allocation/free behavior.

Poem

I wired new rings where packets spin,
I hop through queues—desc by desc—within.
I nudge the PCI, set STATUS right,
Then notify softly through the night.
A tiny leak I spy (pardon me!)—hope the crumbs stay free. 🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8caaccb and ac5d3f8.

📒 Files selected for processing (2)
  • mm/security/Cerberus.c (7 hunks)
  • vfconfig.py (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Development

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
fs/FAT12.c (1)

572-581: Fix memory leak: free cluster_buffer after successful write

The free was removed; there's no other free on the success path. This leaks one full cluster buffer per directory created. Not a double-free: error paths already free before returning.

Apply this diff:

-    // KernelFree(cluster_buffer); - double free?
+    // Done with '.' and '..' cluster buffer
+    KernelFree(cluster_buffer);
🧹 Nitpick comments (9)
drivers/virtio/VirtioBlk.h (1)

1-12: Header looks clean and minimal

Guards and prototypes are fine. Consider adding a write API later for symmetry.

drivers/PCI/PCI.c (1)

96-108: Consider adding null checks for the callback parameter.

The function calls InitializeVirtioBlk directly without checking if the initialization succeeded. Additionally, ensure that device initialization failures don't impact the rest of the PCI enumeration.

Consider adding error handling:

 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);
+            // Consider checking initialization status if InitializeVirtioBlk returns a status code
         }
     }
 }
drivers/virtio/Virtio.h (7)

63-65: Add missing descriptor flag: INDIRECT.

Needed for indirect descriptor tables.

 #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).
+#define VIRTQ_DESC_F_INDIRECT 4 // Descriptor points to a table of descriptors.

6-8: Define device status bits (used with device_status).

These are standard and will be used during feature negotiation/init.

-// Common VirtIO definitions will go here.
-// For example, PCI configuration registers, feature bits, status fields, etc.
+// VirtIO device status bits
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE        0x01
+#define VIRTIO_CONFIG_S_DRIVER             0x02
+#define VIRTIO_CONFIG_S_DRIVER_OK          0x04
+#define VIRTIO_CONFIG_S_FEATURES_OK        0x08
+#define VIRTIO_CONFIG_S_DEVICE_NEEDS_RESET 0x40
+#define VIRTIO_CONFIG_S_FAILED             0x80

92-99: Expose block response status codes and response byte.

Drivers need the status byte in the third descriptor of a request.

 struct VirtioBlkReq {
     uint32_t type;
     uint32_t reserved;
     uint64_t sector;
 } __attribute__((packed));
 
+// VirtIO block status codes and response byte
+#define VIRTIO_BLK_S_OK     0
+#define VIRTIO_BLK_S_IOERR  1
+#define VIRTIO_BLK_S_UNSUPP 2
+struct VirtioBlkResp {
+    uint8_t status;
+} __attribute__((packed));

18-28: Optional: add Notify capability wrapper (notify_off_multiplier).

Most drivers need this to compute the notify MMIO offset.

 } __attribute__((packed));
 
+// VirtIO PCI Notify capability (cfg_type = VIRTIO_CAP_NOTIFY_CFG)
+struct VirtioPciNotifyCap {
+    struct VirtioPciCap cap;
+    uint32_t notify_off_multiplier;
+} __attribute__((packed));

I can wire this where you parse capabilities if helpful.


101-102: Add compile-time layout checks.

Guards against accidental struct drift.

 #endif //VOIDFRAME_VIRTIO_H
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+_Static_assert(sizeof(struct VirtioPciCap) == 16, "VirtioPciCap must be 16 bytes");
+_Static_assert(sizeof(struct VirtqDesc) == 16, "VirtqDesc must be 16 bytes");
+#endif

4-4: Use system header form for stdint.

Minor style/readability.

-#include "stdint.h"
+#include <stdint.h>

32-56: Rename struct fields and update references to match VirtIO spec terminology

— drivers/virtio/Virtio.h
@@ -52,2 +52,2
-    uint64_t queue_driver;
-    uint64_t queue_device;
+    uint64_t queue_avail;
+    uint64_t queue_used;
— drivers/virtio/VirtioBlk.c
@@ -177,2 +177,2
-    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);
+    common_cfg_ptr->queue_avail  = VIRT_TO_PHYS((uint64_t)vq_avail_ring);
+    common_cfg_ptr->queue_used   = VIRT_TO_PHYS((uint64_t)vq_used_ring);

Aligns field names with the VirtIO spec and reduces ambiguity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0ec796d and 6276305.

📒 Files selected for processing (7)
  • drivers/PCI/PCI.c (5 hunks)
  • drivers/virtio/Virtio.h (1 hunks)
  • drivers/virtio/VirtioBlk.c (1 hunks)
  • drivers/virtio/VirtioBlk.h (1 hunks)
  • fs/FAT12.c (1 hunks)
  • kernel/core/Kernel.c (3 hunks)
  • meson.build (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-30T07:32:52.301Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#99
File: meson.build:103-103
Timestamp: 2025-08-30T07:32:52.301Z
Learning: FAT12 filesystem has a hard mathematical limit of 4,086 clusters due to 12-bit cluster addressing. This means FAT12 cannot handle disk sizes larger than approximately 4MB, making 128MB disks incompatible with FAT12 format. The user's meson.build was creating 128M disks with FAT12 format (`mkfs.fat -F 12`), which caused kernel panics when accessing files. The solution is to either use smaller disk sizes (≤4MB, preferably 1440K for traditional floppy compatibility) with FAT12, or use FAT16/FAT32 for larger disk sizes.

Applied to files:

  • fs/FAT12.c
📚 Learning: 2025-08-17T08:16:43.539Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#93
File: kernel/memory/VMem.c:72-79
Timestamp: 2025-08-17T08:16:43.539Z
Learning: In VoidFrame kernel, VMemGetPhysAddr and related page table walking functions were causing panics because they assumed identity mapping existed for physical addresses < IDENTITY_MAP_SIZE (4GB), but the bootloader doesn't provide this 1:1 mapping. The fix is to remove all identity mapping assumptions and always use PHYS_TO_VIRT() for page table access in functions like VMemGetPageTablePhys, VMemMap, VMemMapHuge, VMemGetPhysAddr, VMemUnmap, VMemMapMMIO, and VMemUnmapMMIO.

Applied to files:

  • kernel/core/Kernel.c
🧬 Code graph analysis (4)
drivers/virtio/VirtioBlk.c (4)
drivers/PCI/PCI.c (3)
  • PciConfigReadByte (27-30)
  • PciConfigReadDWord (14-25)
  • PciConfigWriteDWord (32-48)
kernel/etc/Console.c (2)
  • PrintKernel (154-171)
  • PrintKernelHex (207-230)
mm/VMem.c (4)
  • VMemAlloc (243-309)
  • VMemUnmap (516-555)
  • VMemFree (311-375)
  • VMemMapMMIO (587-672)
kernel/atomic/Atomics.c (1)
  • AtomicInc (6-8)
drivers/virtio/VirtioBlk.h (1)
drivers/virtio/VirtioBlk.c (2)
  • InitializeVirtioBlk (38-184)
  • VirtioBlkRead (186-242)
drivers/PCI/PCI.c (2)
kernel/etc/Console.c (2)
  • PrintKernel (154-171)
  • PrintKernelHex (207-230)
drivers/virtio/VirtioBlk.c (1)
  • InitializeVirtioBlk (38-184)
kernel/core/Kernel.c (12)
kernel/etc/Console.c (3)
  • PrintKernel (154-171)
  • PrintKernelSuccess (185-190)
  • PrintKernelWarning (199-204)
drivers/PS2.c (1)
  • PS2Init (62-116)
kernel/etc/Shell.c (1)
  • ShellInit (990-992)
fs/VFRFS.c (1)
  • FsInit (77-91)
fs/VFS.c (1)
  • VfsInit (43-78)
kernel/process/Process.c (1)
  • ProcessInit (1654-1733)
drivers/ISA/ISA.c (3)
  • IsaInitBus (65-75)
  • IsaAutoDetect (138-172)
  • IsaPrintDevices (200-215)
drivers/PCI/PCI.c (1)
  • PciEnumerate (122-129)
drivers/ethernet/RTL8139.c (1)
  • Rtl8139_Init (11-87)
drivers/LPT/LPT.c (1)
  • LPT_Init (16-32)
mm/PMem.c (1)
  • GetDetailedMemoryStats (320-370)
mm/StackGuard.c (1)
  • StackGuardInit (10-15)
🔇 Additional comments (16)
kernel/core/Kernel.c (11)

567-571: Gating CPU feature validation behind VF_CONFIG_VM_HOST looks good

Keeps noisy CPUID warnings out of VM-hosted builds.


621-626: PS/2 init under feature flag is fine

No issues; avoids touching legacy input when unused.


628-633: Shell init gating is reasonable

Matches optional userland bring-up.


660-664: INITRD gating OK

Keeps stage-1 optional.


671-676: Memory layout validation and huge-page probe behind protection flag looks fine

Sequence is sensible.


678-683: Process init under MLFQ flag is fine

No concerns.


685-694: ISA bus init/scan gating is fine

Order (init → autodetect → print) is correct.


695-703: PCI scan + RTL8139 init gating looks good

Note: VirtIO handler is invoked from PCI enumeration; ensure MMIO mapping honors no-identity assumptions elsewhere.


728-729: IRQ unmasking placement

Unmasks after IDT/PIC/PIT and major device inits. Looks acceptable; just be aware PS/2 may start firing immediately.


717-726: Ignore CET bit removal suggestion
SetupMemoryProtection correctly checks CPUID.(EAX=7,ECX=0):ECX[7] before setting CR4.CET; Intel architecture and Linux kernel docs confirm CR4.CET is an architecturally-defined prerequisite for any CET feature (IBT/Shadow Stack), and MSR writes alone do not enable CET (patchwork.kernel.org)

Likely an incorrect or invalid review comment.


635-653: Manual verification required: inspect build/image scripts for FAT12 volume creation
No occurrences of mkfs.fat -F 12, explicit size allocations (e.g., 128M), or QEMU FAT12 flags were found in code or build tooling beyond a README mention. Please review your Meson, shell, or other image-generation scripts to ensure no oversized FAT12 images are still being produced, which could trigger kernel panics.

drivers/PCI/PCI.c (2)

27-30: LGTM! Clean 4-byte aligned read implementation.

The byte extraction logic correctly handles the offset within the aligned DWord using shift operations.


125-127: Appropriate use of feature-gated VirtIO scanning.

The conditional compilation ensures VirtIO support is only included when explicitly enabled via the build system.

meson.build (3)

67-67: LGTM! VirtIO driver properly integrated into build system.

The VirtIO include directory and source file are correctly added to the build configuration.

Also applies to: 126-126


140-149: Well-structured feature flags for modular kernel configuration.

The VF_CONFIG flags provide good granularity for enabling/disabling kernel features at build time.


239-240: VirtIO disk properly configured in QEMU run target.

The VirtIO block device is correctly set up with modern (non-legacy) mode.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
mm/security/Cerberus.c (2)

37-65: Bounds-check process_id before indexing process_info

A malformed report could corrupt memory. Guard before touching process_info[pid].

 void CerberusLogViolation(CerberusViolationReport* report) {
     if (!g_cerberus_state.is_initialized || !report) return;
+    if (report->process_id >= CERBERUS_MAX_PROCESSES) return;

54-64: Log path mismatch: Init creates RuntimeServices/Cerberus/ but logging appends to /ProcINFO/Cerberus/*

As written, VFS append will likely fail. Use a single path source and avoid FormatS’s static buffer in init.

-#ifdef VF_CONFIG_CERBERUS_VFS_LOGGING
-    // VFS logging
-    char log_entry[256];
+#ifdef VF_CONFIG_CERBERUS_VFS_LOGGING
+    // VFS logging
+    char log_entry[256];
+    char vio_path[256];
     FormatA(log_entry, sizeof(log_entry),
            "TICK=%lu PID=%d TYPE=%d ADDR=0x%lx RIP=0x%lx DESC=%s\n",
            system_ticks, report->process_id, report->violation_type,
            report->fault_address, report->rip, report->description);
-
-    VfsAppendFile("/ProcINFO/Cerberus/violations.log", log_entry, StringLength(log_entry));
+    FormatA(vio_path, sizeof(vio_path), "%s/Cerberus/violations.log", RuntimeServices);
+    VfsAppendFile(vio_path, log_entry, StringLength(log_entry));
 #endif
 #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));
+    // Create logging directories in VFS (avoid FormatS static buffer)
+    char base[256], vio[256], wl[256];
+    FormatA(base, sizeof(base), "%s/Cerberus", RuntimeServices);
+    FormatA(vio,  sizeof(vio),  "%s/violations.log", base);
+    FormatA(wl,   sizeof(wl),   "%s/watchlist.log",  base);
+    VfsCreateDir(base);
+    VfsCreateFile(vio);
+    VfsCreateFile(wl);
 #endif

Also applies to: 85-91

🧹 Nitpick comments (8)
kernel/etc/Shell.c (3)

139-142: LGTM: explicit unused-arg mark

Nice touch. Tiny style nit: remove the extra blank line for consistency with nearby handlers.

 static void ARPTestHandler(const char * args) {
     (void)args;
-    
     CreateProcess(ArpRequestTestProcess);
 }

225-229: LGTM: unused-arg mark

Same nit on trailing blank line.

 static void LsPCIHandler(const char * args) {
     (void)args;
-    
     CreateProcess(PciEnumerate);
 }

268-272: LGTM: unused-arg mark

Keep, and drop the extra blank line for consistency.

 static void LsUSBHandler(const char * args) {
-    (void)args;
-    
+    (void)args;
     CreateProcess(xHCIEnumerate);
 }
mm/security/Cerberus.h (1)

69-71: Good: feature-gated public API for threat reporting

Header gating is correct. Add a brief contract comment warning this API must not perform VFS or blocking work in scheduler/interrupt context; it should enqueue work instead. This avoids re‑introducing the kernel panics documented earlier.

 #ifdef VF_CONFIG_CERBERUS_THREAT_REPORTING
-void CerberusReportThreat(uint32_t pid, MemorySecurityViolation violation);
+// Note: Must be non-blocking and safe in scheduler/IRQ context.
+// Prefer queuing a report for Astra rather than direct VFS I/O here.
+void CerberusReportThreat(uint32_t pid, MemorySecurityViolation violation);
 #endif
docs/ARCHITECTURE.md (1)

414-431: Document Cerberus runtime gates to prevent scheduler-context VFS I/O

Add the two new (optional) flags so users don’t enable them blindly. Recommend default-off and note they enqueue work rather than doing VFS inline.

       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_PANIC_OVERRIDE',
+       # '-DVF_CONFIG_USE_CERBERUS',
+       # '-DVF_CONFIG_CERBERUS_VFS_LOGGING',         # Off by default; never in scheduler/IRQ path
+       # '-DVF_CONFIG_CERBERUS_THREAT_REPORTING',    # Off by default; should enqueue work
+       # '-DVF_CONFIG_PANIC_OVERRIDE',
       ]
mm/security/Cerberus.c (1)

299-315: Defer VFS writes to non-IRQ context
astra_path is already defined in kernel/process/Process.c, so the extern won’t break linking; instead of calling VfsWriteFile directly from interrupt/scheduler context, enqueue threat reports and perform file writes in a worker thread.

meson.build (2)

140-149: Many feature gates enabled at once — verify boot matrix.

Enabling VIRTIO, PCI, ISA, LPT, PS/2, INITRD, IDE, MLFQ, and ENFORCE_MEMORY_PROTECTION together widens kernel surface and may re-trigger Cerberus-related panics if the code paths are still sensitive during early init or process registration.

  • Consider a “virtio_dev” preset flag set to toggle only the minimal set needed for VirtIO bring-up.
  • Add a dedicated flag to defer Cerberus stack-canary install and all VFS writes during process registration (e.g., -DVF_CONFIG_CERB_DEFER_CANARY, -DVF_CONFIG_CERB_NO_VFS).
    Apply if you want Meson to carry these toggles:
 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_CERB_DEFER_CANARY',
+  '-DVF_CONFIG_CERB_NO_VFS',
 ]

254-259: Use FAT16 for 128M img — correct; add a note to avoid FAT12 mounts.

128M with -F 16 is appropriate. If the kernel only implements FAT12 today, avoid auto-mounting this Virtio disk or gate mount attempts; otherwise, consider adding FAT16 support before mounting it in-kernel.

Optionally document the rationale inline:

 run_target('virtio-img',
     command: ['sh', '-c',
-              qemu_img.full_path() + ' create -f raw VirtioDisk.img 128M' + ' && ' +
-              mkfs_fat.full_path() + ' -F 16 VirtioDisk.img'
+              qemu_img.full_path() + ' create -f raw VirtioDisk.img 128M' + ' && ' +
+              # 128M -> FAT16 (FAT12 too small; FAT32 unnecessary here)
+              mkfs_fat.full_path() + ' -F 16 VirtioDisk.img'
     ]
 )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6276305 and a909af2.

📒 Files selected for processing (10)
  • README.md (1 hunks)
  • docs/ARCHITECTURE.md (1 hunks)
  • drivers/virtio/Virtio.h (1 hunks)
  • drivers/virtio/VirtioBlk.c (1 hunks)
  • kernel/etc/Shell.c (4 hunks)
  • kernel/process/Process.c (1 hunks)
  • meson.build (5 hunks)
  • mm/security/Cerberus.c (9 hunks)
  • mm/security/Cerberus.h (1 hunks)
  • mm/trace/StackTrace.c (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • kernel/process/Process.c
  • mm/trace/StackTrace.c
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • drivers/virtio/VirtioBlk.c
  • drivers/virtio/Virtio.h
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-09-01T08:01:39.944Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#105
File: meson.build:252-257
Timestamp: 2025-09-01T08:01:39.944Z
Learning: Cerberus memory protection system causes kernel panics not because of fault analysis but because it performs VFS operations (VfsCreateDir, VfsAppendFile, VfsWriteFile) in critical scheduler paths. CerberusPreScheduleCheck() runs before every context switch and CerberusTick() runs every 10 scheduler ticks, both potentially triggering VFS I/O that can cause page faults. VFS operations should be deferred or made optional to avoid crashes in scheduler context.

Applied to files:

  • mm/security/Cerberus.h
  • meson.build
  • mm/security/Cerberus.c
📚 Learning: 2025-09-01T08:17:56.738Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#105
File: meson.build:252-257
Timestamp: 2025-09-01T08:17:56.738Z
Learning: In VoidFrame's Cerberus security system, CerberusRegisterProcess() causes kernel panics because CerberusInstallStackCanary() performs direct memory writes (*canary_ptr = STACK_CANARY_VALUE) during process creation. The stack memory may not be fully mapped/accessible at this point, causing page faults in critical kernel context. The fix is to either defer canary installation, add memory mapping validation, or skip canary installation during process registration.

Applied to files:

  • mm/security/Cerberus.h
  • meson.build
  • mm/security/Cerberus.c
📚 Learning: 2025-08-30T07:32:52.301Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#99
File: meson.build:103-103
Timestamp: 2025-08-30T07:32:52.301Z
Learning: FAT12 filesystem has a hard mathematical limit of 4,086 clusters due to 12-bit cluster addressing. This means FAT12 cannot handle disk sizes larger than approximately 4MB, making 128MB disks incompatible with FAT12 format. The user's meson.build was creating 128M disks with FAT12 format (`mkfs.fat -F 12`), which caused kernel panics when accessing files. The solution is to either use smaller disk sizes (≤4MB, preferably 1440K for traditional floppy compatibility) with FAT12, or use FAT16/FAT32 for larger disk sizes.

Applied to files:

  • meson.build
📚 Learning: 2025-08-31T07:06:36.977Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#101
File: kernel/etc/Shell.c:829-837
Timestamp: 2025-08-31T07:06:36.977Z
Learning: assembler-0 is working on optimizing ramfs performance in VoidFrame kernel and wants to implement proper filesystem characteristics like faster lookups, better memory management, and advanced features like copy-on-write and caching.

Applied to files:

  • meson.build
📚 Learning: 2025-08-13T08:43:54.750Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#80
File: README.md:7-8
Timestamp: 2025-08-13T08:43:54.750Z
Learning: User assembler-0 is working on VoidFrame kernel with a tight deadline (2-3 days before summer ends) and specifically requested runtime safety checks similar to __stack_chk_fail but for deadlocks and other kernel issues. The kernel already has extensive safety mechanisms including stack canaries, guard pages, heap integrity checks, and process security validation.

Applied to files:

  • meson.build
📚 Learning: 2025-08-31T14:19:11.338Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: docs/ARCHITECHTURE.md:1-3
Timestamp: 2025-08-31T14:19:11.338Z
Learning: assembler-0 wants to implement deep fault tracing for VoidFrame kernel exceptions (Page Fault, General Protection Fault, Invalid Opcode) instead of just panicking. The current interrupt handler has complete register state available in the Registers struct (defined in arch/x86_64/cpu/Cpu.h) including RBP for stack walking, RIP for fault location, and error codes for analysis.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T01:10:22.088Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: README.md:9-9
Timestamp: 2025-09-01T01:10:22.088Z
Learning: VoidFrame's interrupt handlers in arch/x86_64/interrupts/Interrupts.asm only save basic GPRs and segment registers, missing critical registers for deep fault tracing: control registers (CR0/CR2/CR3/CR4), SIMD state (XMM/YMM/ZMM), debug registers (DR0-DR7), and extended FPU state. The CPU initialization code enables SSE/AVX/XSAVE features but interrupt handlers don't preserve this extended state. Enhanced fault tracing requires selective extended state saving for critical exceptions (ISR 6, 8, 13, 14) while keeping lightweight handling for regular interrupts.

Applied to files:

  • meson.build
📚 Learning: 2025-08-14T02:11:58.963Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#82
File: kernel/process/Process.h:0-0
Timestamp: 2025-08-14T02:11:58.963Z
Learning: In VoidFrame kernel's FastMemcpy implementation (kernel/memory/MemOps.c), memory corruption occurs under high load due to interrupts occurring between SSE2 movdqu load and store instructions, corrupting XMM register state. The fix requires disabling interrupts around SSE operations and adding memory barriers (sfence) to ensure stores complete atomically.

Applied to files:

  • meson.build
📚 Learning: 2025-08-17T08:16:43.539Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#93
File: kernel/memory/VMem.c:72-79
Timestamp: 2025-08-17T08:16:43.539Z
Learning: In VoidFrame kernel, VMemGetPhysAddr and related page table walking functions were causing panics because they assumed identity mapping existed for physical addresses < IDENTITY_MAP_SIZE (4GB), but the bootloader doesn't provide this 1:1 mapping. The fix is to remove all identity mapping assumptions and always use PHYS_TO_VIRT() for page table access in functions like VMemGetPageTablePhys, VMemMap, VMemMapHuge, VMemGetPhysAddr, VMemUnmap, VMemMapMMIO, and VMemUnmapMMIO.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T01:10:22.088Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: README.md:9-9
Timestamp: 2025-09-01T01:10:22.088Z
Learning: The current VoidFrame Registers struct in arch/x86_64/cpu/Cpu.h only saves basic GPRs, segment registers, and exception context (interrupt_number, error_code, rip, cs, rflags, rsp, ss). It's missing critical registers for deep fault tracing: SIMD registers (XMM/YMM/ZMM), control registers (CR0/CR2/CR3/CR4), debug registers (DR0-DR7), and extended FPU state. The struct has a "DO NOT TOUCH" comment indicating it must match interrupt ASM stack layout.

Applied to files:

  • meson.build
📚 Learning: 2025-08-10T06:22:28.816Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#62
File: kernel/core/Panic.c:69-79
Timestamp: 2025-08-10T06:22:28.816Z
Learning: In VoidFrame kernel, panic functions must call "asm volatile("cli")" as the very first instruction to disable interrupts immediately. Without this, if interrupts are enabled (after "sti"), an interrupt can fire during panic handling causing the panic to fail, hang, or behave unpredictably. This must be done in ALL panic entry points: Panic(), PanicWithCode(), PanicWithContext(), PanicFromInterrupt(), and at the start of KernelPanicHandler().

Applied to files:

  • meson.build
📚 Learning: 2025-08-14T02:11:27.395Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#82
File: kernel/process/Process.h:0-0
Timestamp: 2025-08-14T02:11:27.395Z
Learning: In VoidFrame kernel, FastMemcpy was using SSE2 movdqu instructions without preserving XMM registers, causing crashes when called from interrupt context (like the scheduler's FastSchedule function). The fix is to use only general-purpose registers with 64-bit unrolled copies to maintain performance while being interrupt-safe.

Applied to files:

  • meson.build
🧬 Code graph analysis (2)
mm/security/Cerberus.h (1)
mm/security/Cerberus.c (1)
  • CerberusReportThreat (300-314)
mm/security/Cerberus.c (3)
fs/VFS.c (2)
  • VfsCreateDir (245-263)
  • VfsCreateFile (221-243)
kernel/etc/Format.c (1)
  • FormatS (384-391)
kernel/etc/Console.c (2)
  • PrintKernelErrorF (250-257)
  • PrintKernelWarningF (241-248)
🔇 Additional comments (7)
kernel/etc/Shell.c (1)

5-5: Keep #include "Cerberus.h" as-is
Meson’s inc_dirs already includes src_root/mm/security, so Cerberus.h will be found without a relative path change.

mm/security/Cerberus.c (2)

115-118: Good: disabling canary install at registration avoids early-page-faults

This aligns with prior crashes. Consider deferring canary install until after stack mapping is confirmed.


216-236: I've added scripts to:

  • Locate and inspect CerberusReportThreat (ensure VFS operations occur there)
  • Search for any Vfs* calls in that function
  • Review the scheduler pre-switch hook CerberusPreScheduleCheck where reporting is invoked

Once results are available, I’ll confirm whether the threat-reporting path still performs VFS in a critical context and whether the return behavior needs adjustment.

meson.build (4)

67-67: Virtio include path added — looks good.

No issues; aligns with new driver sources.


155-156: Keeping Cerberus VFS logging and threat reporting disabled is prudent.

Given prior panics from VFS ops in scheduler/process paths, leaving these off avoids regressions while VirtIO bring-up proceeds.


241-243: Virtio disk attached with modern-only mode — ensure driver supports non-transitional.

Using virtio-blk-pci with disable-legacy=on is great if the driver negotiates V1.0 features correctly; otherwise the device won’t probe.

You can keep compatibility during bring-up by dropping the knob:

- '-device', 'virtio-blk-pci,drive=virtio_disk,disable-legacy=on',
+ '-device', 'virtio-blk-pci,drive=virtio_disk',

126-126: Virtio block driver source wired into the build. LGTM.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (15)
.gitignore (1)

9-10: LGTM; consider a couple more Python ignores.

.venv is perfect. Optional: add __pycache__/, *.pyc, and .pytest_cache/ to avoid stray artifacts from vfconfig.py.

 target
 .venv
+__pycache__/
+*.pyc
+.pytest_cache/
meson.build (2)

155-157: Avoid VFS writes from scheduler/early paths; disable Cerberus VFS logging by default.

Given prior crashes from Cerberus VFS activity in critical paths, suggest shipping with VFS logging off by default and re-enabling once deferred/async logging is in place.

     '-DVF_CONFIG_USE_CERBERUS',
-    '-DVF_CONFIG_CERBERUS_VFS_LOGGING',
+    # '-DVF_CONFIG_CERBERUS_VFS_LOGGING',
     '-DVF_CONFIG_CERBERUS_THREAT_REPORTING',

241-243: QEMU VirtIO wiring looks good.

-drive ... if=none + -device virtio-blk-pci,drive=virtio_disk,disable-legacy=on is correct. Optional: add bootorder= or -device virtio-blk-pci,serial=... if you want deterministic device IDs in logs.

vfconfig.py (9)

6-15: Import ClassVar for static class attributes.

To satisfy linters and clarify intent for class-level BINDINGS/CSS, import ClassVar.

-from typing import List, Tuple, Optional
+from typing import List, Tuple, Optional, ClassVar

30-34: Annotate class-level BINDINGS with ClassVar.

Prevents mutable-class-attr warnings (RUF012).

-    BINDINGS = [
+    BINDINGS: ClassVar[list[Binding]] = [
         ("y", "confirm", "Yes"),
         ("n", "cancel", "No"),
         ("escape", "cancel", "Cancel"),
     ]

89-128: Annotate CSS as ClassVar[str].

Avoids mutable class attribute lint issues.

-    CSS = """
+    CSS: ClassVar[str] = """

130-136: Annotate app-level BINDINGS as ClassVar.

Same rationale as above.

-    BINDINGS = [
+    BINDINGS: ClassVar[list[Binding]] = [
         ("q", "quit", "Quit"),
         ("s", "save", "Save"),
         ("r", "reload", "Reload"),
         ("a", "toggle_all", "Toggle All"),
         ("?", "help", "Help"),
     ]

166-170: Narrow exception type when loading file.

Catching broad Exception (BLE001). Limit to OSError to reduce noise.

-        except Exception as e:
+        except OSError as e:
             self.notify(f"Error loading file: {e}", severity="error")

258-268: Use the message underscore and update the correct stats widget.

Fix unused param (ARG002) and ensure you update #stats_display instead of the first .stats (which might be the filename banner).

-    def on_config_flag_changed(self, message: ConfigFlagChanged) -> None:
+    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)
+        # Update stats display
+        stats_widget = self.query_one("#stats_display", expect_type=Static)
+        stats_widget.update(stats_text)

269-281: Narrow exception type on save.

Same BLE001 issue; prefer OSError to avoid masking logic errors.

-                except Exception as e:
+                except OSError as e:
                     self.notify(f"Error saving file: {e}", severity="error")

295-303: Remove unused local (F841).

current_comment isn’t used.

-                    current_comment = match.group(1) or ""
                     flag_part = match.group(2)
                     desc_comment = match.group(3) or ""

324-345: Toggle-all checkbox sync is fine; micro-UX improvement.

Consider deferring update_display() until after all checkbox values are flipped to avoid intermediate reflows; current approach is acceptable.

arch/x86_64/idt/Idt.c (3)

272-273: Duplicate assignment to Flags.

g_Idt[num].Flags = flags; appears twice; remove one.

     g_Idt[num].Reserved = 0;
     g_Idt[num].Flags = flags;
-    g_Idt[num].Flags = flags;

268-277: Add a bounds check for safety in IdtSetGate.

Defensive guard avoids accidental out-of-range writes if callers change.

 void IdtSetGate(uint8_t num, uint64_t base, uint16_t sel, uint8_t flags) {
+    if (num >= IDT_ENTRIES) return;
     g_Idt[num].BaseLow = (base & 0xFFFF);

5-6: Consider restricting IDT globals’ linkage.

Mark g_Idt/g_IdtPtr as static unless other translation units need them.

-struct IdtEntry g_Idt[IDT_ENTRIES];
-struct IdtPtr   g_IdtPtr;
+static struct IdtEntry g_Idt[IDT_ENTRIES];
+static struct IdtPtr   g_IdtPtr;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a909af2 and 8caaccb.

📒 Files selected for processing (4)
  • .gitignore (1 hunks)
  • arch/x86_64/idt/Idt.c (2 hunks)
  • meson.build (5 hunks)
  • vfconfig.py (1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-08-30T07:32:52.301Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#99
File: meson.build:103-103
Timestamp: 2025-08-30T07:32:52.301Z
Learning: FAT12 filesystem has a hard mathematical limit of 4,086 clusters due to 12-bit cluster addressing. This means FAT12 cannot handle disk sizes larger than approximately 4MB, making 128MB disks incompatible with FAT12 format. The user's meson.build was creating 128M disks with FAT12 format (`mkfs.fat -F 12`), which caused kernel panics when accessing files. The solution is to either use smaller disk sizes (≤4MB, preferably 1440K for traditional floppy compatibility) with FAT12, or use FAT16/FAT32 for larger disk sizes.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T08:01:39.944Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#105
File: meson.build:252-257
Timestamp: 2025-09-01T08:01:39.944Z
Learning: Cerberus memory protection system causes kernel panics not because of fault analysis but because it performs VFS operations (VfsCreateDir, VfsAppendFile, VfsWriteFile) in critical scheduler paths. CerberusPreScheduleCheck() runs before every context switch and CerberusTick() runs every 10 scheduler ticks, both potentially triggering VFS I/O that can cause page faults. VFS operations should be deferred or made optional to avoid crashes in scheduler context.

Applied to files:

  • meson.build
📚 Learning: 2025-08-31T07:06:36.977Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#101
File: kernel/etc/Shell.c:829-837
Timestamp: 2025-08-31T07:06:36.977Z
Learning: assembler-0 is working on optimizing ramfs performance in VoidFrame kernel and wants to implement proper filesystem characteristics like faster lookups, better memory management, and advanced features like copy-on-write and caching.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T08:17:56.738Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#105
File: meson.build:252-257
Timestamp: 2025-09-01T08:17:56.738Z
Learning: In VoidFrame's Cerberus security system, CerberusRegisterProcess() causes kernel panics because CerberusInstallStackCanary() performs direct memory writes (*canary_ptr = STACK_CANARY_VALUE) during process creation. The stack memory may not be fully mapped/accessible at this point, causing page faults in critical kernel context. The fix is to either defer canary installation, add memory mapping validation, or skip canary installation during process registration.

Applied to files:

  • meson.build
📚 Learning: 2025-08-13T08:43:54.750Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#80
File: README.md:7-8
Timestamp: 2025-08-13T08:43:54.750Z
Learning: User assembler-0 is working on VoidFrame kernel with a tight deadline (2-3 days before summer ends) and specifically requested runtime safety checks similar to __stack_chk_fail but for deadlocks and other kernel issues. The kernel already has extensive safety mechanisms including stack canaries, guard pages, heap integrity checks, and process security validation.

Applied to files:

  • meson.build
📚 Learning: 2025-08-31T14:19:11.338Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: docs/ARCHITECHTURE.md:1-3
Timestamp: 2025-08-31T14:19:11.338Z
Learning: assembler-0 wants to implement deep fault tracing for VoidFrame kernel exceptions (Page Fault, General Protection Fault, Invalid Opcode) instead of just panicking. The current interrupt handler has complete register state available in the Registers struct (defined in arch/x86_64/cpu/Cpu.h) including RBP for stack walking, RIP for fault location, and error codes for analysis.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T01:10:22.088Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: README.md:9-9
Timestamp: 2025-09-01T01:10:22.088Z
Learning: VoidFrame's interrupt handlers in arch/x86_64/interrupts/Interrupts.asm only save basic GPRs and segment registers, missing critical registers for deep fault tracing: control registers (CR0/CR2/CR3/CR4), SIMD state (XMM/YMM/ZMM), debug registers (DR0-DR7), and extended FPU state. The CPU initialization code enables SSE/AVX/XSAVE features but interrupt handlers don't preserve this extended state. Enhanced fault tracing requires selective extended state saving for critical exceptions (ISR 6, 8, 13, 14) while keeping lightweight handling for regular interrupts.

Applied to files:

  • meson.build
  • arch/x86_64/idt/Idt.c
📚 Learning: 2025-08-14T02:11:58.963Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#82
File: kernel/process/Process.h:0-0
Timestamp: 2025-08-14T02:11:58.963Z
Learning: In VoidFrame kernel's FastMemcpy implementation (kernel/memory/MemOps.c), memory corruption occurs under high load due to interrupts occurring between SSE2 movdqu load and store instructions, corrupting XMM register state. The fix requires disabling interrupts around SSE operations and adding memory barriers (sfence) to ensure stores complete atomically.

Applied to files:

  • meson.build
📚 Learning: 2025-08-17T08:16:43.539Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#93
File: kernel/memory/VMem.c:72-79
Timestamp: 2025-08-17T08:16:43.539Z
Learning: In VoidFrame kernel, VMemGetPhysAddr and related page table walking functions were causing panics because they assumed identity mapping existed for physical addresses < IDENTITY_MAP_SIZE (4GB), but the bootloader doesn't provide this 1:1 mapping. The fix is to remove all identity mapping assumptions and always use PHYS_TO_VIRT() for page table access in functions like VMemGetPageTablePhys, VMemMap, VMemMapHuge, VMemGetPhysAddr, VMemUnmap, VMemMapMMIO, and VMemUnmapMMIO.

Applied to files:

  • meson.build
📚 Learning: 2025-09-01T01:10:22.088Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: README.md:9-9
Timestamp: 2025-09-01T01:10:22.088Z
Learning: The current VoidFrame Registers struct in arch/x86_64/cpu/Cpu.h only saves basic GPRs, segment registers, and exception context (interrupt_number, error_code, rip, cs, rflags, rsp, ss). It's missing critical registers for deep fault tracing: SIMD registers (XMM/YMM/ZMM), control registers (CR0/CR2/CR3/CR4), debug registers (DR0-DR7), and extended FPU state. The struct has a "DO NOT TOUCH" comment indicating it must match interrupt ASM stack layout.

Applied to files:

  • meson.build
📚 Learning: 2025-08-10T06:22:28.816Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#62
File: kernel/core/Panic.c:69-79
Timestamp: 2025-08-10T06:22:28.816Z
Learning: In VoidFrame kernel, panic functions must call "asm volatile("cli")" as the very first instruction to disable interrupts immediately. Without this, if interrupts are enabled (after "sti"), an interrupt can fire during panic handling causing the panic to fail, hang, or behave unpredictably. This must be done in ALL panic entry points: Panic(), PanicWithCode(), PanicWithContext(), PanicFromInterrupt(), and at the start of KernelPanicHandler().

Applied to files:

  • meson.build
📚 Learning: 2025-08-14T02:11:27.395Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#82
File: kernel/process/Process.h:0-0
Timestamp: 2025-08-14T02:11:27.395Z
Learning: In VoidFrame kernel, FastMemcpy was using SSE2 movdqu instructions without preserving XMM registers, causing crashes when called from interrupt context (like the scheduler's FastSchedule function). The fix is to use only general-purpose registers with 64-bit unrolled copies to maintain performance while being interrupt-safe.

Applied to files:

  • meson.build
📚 Learning: 2025-07-08T00:36:50.297Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#2
File: Kernel/Syscall.c:44-44
Timestamp: 2025-07-08T00:36:50.297Z
Learning: In IdtSetGate function calls, the parameters are: (interrupt_vector, handler_address, selector, flags). The interrupt vector (like 0x80) is the first argument, and the selector (like 0x08 for kernel code segment) is the third argument.

Applied to files:

  • arch/x86_64/idt/Idt.c
🪛 Ruff (0.12.2)
vfconfig.py

30-34: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


130-136: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


168-168: Do not catch blind exception: Exception

(BLE001)


259-259: Unused method argument: message

(ARG002)


278-278: Do not catch blind exception: Exception

(BLE001)


299-299: Local variable current_comment is assigned to but never used

Remove assignment to unused variable current_comment

(F841)

🔇 Additional comments (6)
meson.build (4)

67-67: Include path for VirtIO is correct.


126-126: VirtioBlk wired in; verify driver matches QEMU “modern only”.

You passed virtio-blk-pci,disable-legacy=on below; ensure drivers/virtio/VirtioBlk.c implements the modern (1.0+) PCI capability path and feature negotiation (no transitional I/O port paths).


140-147: Default-enable set looks aggressive; confirm boot stability with Cerberus + protection.

With -DVF_CONFIG_ENFORCE_MEMORY_PROTECTION and -DVF_CONFIG_USE_CERBERUS both on by default, please confirm no early-boot panics (e.g., process registration/stack-canary install) before VFS/VMem are fully ready.


253-259: FAT choice for 128M: FAT16 is valid; ensure kernel expectations.

128M with -F 16 is fine. If the kernel only mounts FAT12 today, avoid auto-mounting this disk until FAT16/32 support lands; otherwise switch to -F 32 if that better fits your testing.

vfconfig.py (1)

229-236: Potential API mismatch: remove_children().

If your Textual version lacks remove_children(), use container.remove(*container.children) or rebuild the container. Verify at runtime.

arch/x86_64/idt/Idt.c (1)

283-287: Incorrect target vector for INT 0x80
INT 0x80 maps to descriptor 128 (isr128), not entry 80 (isr80). If you intend a user-mode syscall via INT 0x80, adjust the DPL on the IdtSetGate(128, (uint64_t)isr128, …) call.

Likely an incorrect or invalid review comment.

extern void isr78();
extern void isr79();
// extern void isr80();
extern void isr80();
Copy link

@coderabbitai coderabbitai bot Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Extern for isr80 added — verify symbol exists and linkage from Interrupts.asm.

Ensure isr80 is actually defined and exported (global/globl isr80) in your ASM so the linker resolves this reference.

Run:


🏁 Script executed:

#!/bin/bash
# Find the interrupts assembly file(s) and confirm isr80 definition/export.
fd -t f -a 'Interrupts.*\.(asm|S|s)'
rg -nP -C2 '^\s*(global|globl)\s+isr80\b|^\s*isr80:\s*$'
# Confirm the IDT wiring call site(s).
rg -nP -C2 'IdtSetGate\(\s*80\s*,'

Length of output: 636


Add missing isr80 export and label in Interrupts.asm
The extern void isr80(); in arch/x86_64/idt/Idt.c wires vector 80 (see IdtSetGate(80, (uint64_t)isr80, …)), but there’s no corresponding global/globl isr80 or isr80: definition in arch/x86_64/interrupts/Interrupts.asm. Add:

    global isr80
isr80:
    ; handler implementation

to avoid unresolved-symbol linker errors.

🤖 Prompt for AI Agents
In arch/x86_64/idt/Idt.c around line 91 there is an extern declaration for isr80
but Interrupts.asm lacks an exported symbol/label; add a global/globl export for
isr80 and a corresponding isr80: label in arch/x86_64/interrupts/Interrupts.asm
(placing the label where other ISR labels are defined) and implement or jump to
the handler body so the linker can resolve the symbol and IdtSetGate(80,
(uint64_t)isr80, …) points to a valid entry.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see, but i think the python script have some problems, its just adds the # no matter if the button is toggled or not, and it doesnt account for the current state when opened, and the choices are SO spaced apart, can you help me fix it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

Let me examine the current implementation to identify and fix the issues you mentioned.

Now let me create a fixed version of the vfconfig.py script that addresses all the issues you mentioned:

Now let me show you the key fixes I made:

@assembler-0, I've identified and fixed the issues you mentioned in the vfconfig.py script:

Key Issues Fixed:

1. Toggle Logic Bug

The generate_updated_content() method wasn't properly checking the flag state. I fixed the logic to:

  • Enable: Remove leading # and whitespace when flag.enabled = True
  • Disable: Add # prefix when flag.enabled = False

2. Initial State Detection Bug

The parse_config_flags() method now correctly detects if a flag is currently enabled by checking not line.strip().startswith('#').

3. UI Spacing Issues

Fixed the CSS to make the interface much more compact:

  • Reduced .flag-container height to 1
  • Removed excessive margins and padding
  • Used proper horizontal layout for checkboxes and labels

4. Additional Improvements

  • Better regex pattern for flag detection
  • Proper indentation preservation when toggling flags
  • Enhanced error handling

The fixed script is saved as vfconfig_fixed.py. You can replace the original by running:

The interface should now be much more compact, correctly show the current state of flags when opened, and properly toggle them when you click the checkboxes.


🏁 Script executed:

#!/bin/bash
# Let's examine the vfconfig.py file to understand the current implementation
cat vfconfig.py

Length of output: 12135


🏁 Script executed:

#!/bin/bash
# Let's look specifically at the toggle logic and CSS styling
echo "=== Toggle Logic in generate_updated_content ==="
sed -n '/def generate_updated_content/,/^    def /p' vfconfig.py | head -30

echo -e "\n=== CSS Styling ==="
sed -n '/CSS = """/,/"""/p' vfconfig.py

echo -e "\n=== Parse Config Flags Logic ==="
sed -n '/def parse_config_flags/,/^    def /p' vfconfig.py | head -20

Length of output: 2952


🏁 Script executed:

#!/bin/bash
# Create the fixed vfconfig.py
cat > vfconfig_fixed.py << 'EOF'
#!/usr/bin/env python3

import re
import sys
from dataclasses import dataclass
from typing import List

from textual.app import App, ComposeResult
from textual.containers import Container, Horizontal, Vertical
from textual.message import Message
from textual.screen import ModalScreen
from textual.widgets import Button, Checkbox, Footer, Header, Label, Static


@dataclass
class ConfigFlag:
    name: str
    enabled: bool
    description: str = ""
    line_number: int = 0


class SaveConfirmScreen(ModalScreen[bool]):
    """Screen with a dialog to confirm save."""

    def compose(self) -> ComposeResult:
        yield Container(
            Label("Save changes to meson.build?", id="question"),
            Horizontal(
                Button("Yes", variant="success", id="yes"),
                Button("No", variant="error", id="no"),
                id="buttons",
            ),
            id="dialog",
        )

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.dismiss(event.button.id == "yes")


class ConfigFlagWidget(Static):
    """A widget to display and edit a config flag."""

    def __init__(self, flag: ConfigFlag, **kwargs):
        super().__init__(**kwargs)
        self.flag = flag

    def compose(self) -> ComposeResult:
        with Horizontal(classes="flag-container"):
            yield Checkbox(self.flag.enabled, id=f"checkbox_{self.flag.name}")
            if self.flag.description:
                yield Label(f"{self.flag.name} - {self.flag.description}", classes="flag-label")
            else:
                yield Label(self.flag.name, classes="flag-label")

    def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
        self.flag.enabled = event.value
        self.post_message(ConfigFlagChanged(self.flag))


class ConfigFlagChanged(Message):
    """Sent when a config flag is changed."""

    def __init__(self, flag: ConfigFlag) -> None:
        self.flag = flag
        super().__init__()


class MesonConfigEditor(App):
    """A Textual app to edit meson config flags."""

    CSS = """
    Screen {
        background: $background;
    }

    #dialog {
        grid-size: 2;
        grid-gutter: 1 2;
        grid-rows: 1fr 3;
        padding: 0 1;
        width: 60;
        height: 11;
        border: thick $background 80%;
        background: $surface;
    }

    #question {
        column-span: 2;
        height: 1fr;
        width: 1fr;
        content-align: center middle;
    }

    #buttons {
        column-span: 2;
        height: 3;
        width: 1fr;
        align: center middle;
    }

    .flag-container {
        height: 1;
        margin: 0 1;
        padding: 0;
    }

    .flag-label {
        margin-left: 2;
        content-align: left middle;
    }

    #stats {
        dock: top;
        height: 1;
        background: $primary;
        color: $text;
        text-align: center;
        padding: 0 1;
    }

    #flags-container {
        scrollbar-gutter: stable;
        height: 1fr;
    }
    """

    BINDINGS = [
        ("q", "quit", "Quit"),
        ("s", "save", "Save"),
        ("r", "reload", "Reload"),
        ("t", "toggle_all", "Toggle All"),
        ("?", "help", "Help"),
    ]

    def __init__(self, filename: str = "meson.build") -> None:
        super().__init__()
        self.filename = filename
        self.flags: List[ConfigFlag] = []
        self.original_content = ""

    def compose(self) -> ComposeResult:
        """Create child widgets for the app."""
        yield Header()
        yield Label("Loading...", id="stats")
        yield Container(id="flags-container")
        yield Footer()

    def on_mount(self) -> None:
        """Called when app starts."""
        self.title = "VoidFrame Config Editor"
        self.load_file()

    def load_file(self) -> None:
        """Load the meson.build file and parse config flags."""
        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.exit(message=f"File {self.filename} not found!")
        except Exception as e:
            self.exit(message=f"Error loading file: {e}")

    def parse_config_flags(self, content: str) -> List[ConfigFlag]:
        """Parse config flags from meson.build content."""
        flags = []
        lines = content.split('\n')
        in_vf_config = False
        
        for i, line in enumerate(lines):
            # Look for vf_config_flags array
            if 'vf_config_flags' in line and '=' in line:
                in_vf_config = True
                continue
            
            if in_vf_config:
                # End of array
                if line.strip() == ']' or (']' in line and not line.strip().startswith('#')):
                    break
                
                # Skip empty lines and pure comments
                if not line.strip() or (line.strip().startswith('#') and not '-D' in line):
                    continue
                
                # Parse flag line
                flag_match = re.search(r"['\"]?(-D[A-Z_]+)['\"]?", line)
                if flag_match:
                    flag_name = flag_match.group(1)
                    # Remove -D prefix for display
                    if flag_name.startswith('-D'):
                        flag_name = flag_name[2:]
                    
                    # Check if line is commented (flag is disabled)
                    enabled = not line.strip().startswith('#')
                    
                    # Extract description from comment
                    description = ""
                    comment_match = re.search(r'#\s*(.+)', line)
                    if comment_match and not comment_match.group(1).strip().startswith('-D'):
                        description = comment_match.group(1).strip()
                    
                    flags.append(ConfigFlag(
                        name=flag_name,
                        enabled=enabled,
                        description=description,
                        line_number=i
                    ))
        
        return sorted(flags, key=lambda f: f.name)

    def update_display(self) -> None:
        """Update the display with current flags."""
        container = self.query_one("#flags-container")
        container.remove_children()
        
        # Update stats
        total = len(self.flags)
        enabled = sum(1 for f in self.flags if f.enabled)
        disabled = total - enabled
        stats_text = f"Total: {total} | Enabled: {enabled} | Disabled: {disabled}"
        self.query_one("#stats").update(stats_text)
        
        # Add flag widgets
        with container.batch():
            for flag in self.flags:
                container.mount(ConfigFlagWidget(flag))

    def on_config_flag_changed(self, message: ConfigFlagChanged) -> None:
        """Called when a config flag is changed."""
        # Update stats display
        total = len(self.flags)
        enabled = sum(1 for f in self.flags if f.enabled)
        disabled = total - enabled
        stats_text = f"Total: {total} | Enabled: {enabled} | Disabled: {disabled}"
        self.query_one("#stats").update(stats_text)

    def action_save(self) -> None:
        """Save the current configuration."""
        def check_save(save_confirmed: bool) -> None:
            if save_confirmed:
                try:
                    new_content = self.generate_updated_content()
                    with open(self.filename, 'w') as f:
                        f.write(new_content)
                    self.notify("Configuration saved!")
                except Exception as e:
                    self.notify(f"Error saving: {e}", severity="error")

        self.push_screen(SaveConfirmScreen(), check_save)

    def generate_updated_content(self) -> str:
        """Generate updated file content with current flag states."""
        lines = self.original_content.split('\n')
        flag_dict = {f.name: f for f in self.flags}
        
        for i, line in enumerate(lines):
            # Skip if not in a flag line
            flag_match = re.search(r"['\"]?-D([A-Z_]+)['\"]?", line)
            if not flag_match:
                continue
            
            flag_name = flag_match.group(1)
            if flag_name in flag_dict:
                flag = flag_dict[flag_name]
                
                if flag.enabled:
                    # Enable: remove leading # and whitespace
                    if line.strip().startswith('#'):
                        # Find the # and remove it along with following whitespace
                        hash_pos = line.find('#')
                        indent = line[:hash_pos]
                        rest = line[hash_pos + 1:].lstrip()
                        lines[i] = indent + rest
                else:
                    # Disable: add # if not already there
                    if not line.strip().startswith('#'):
                        # Find first non-whitespace char and add # before it
                        stripped = line.lstrip()
                        indent = line[:len(line) - len(stripped)]
                        lines[i] = indent + '# ' + stripped
        
        return '\n'.join(lines)

    def action_reload(self) -> None:
        """Reload the file."""
        self.load_file()
        self.notify("Configuration reloaded!")

    def action_toggle_all(self) -> None:
        """Toggle all flags."""
        enabled_count = sum(1 for f in self.flags if f.enabled)
        new_state = enabled_count < len(self.flags) / 2  # Enable if less than half are enabled
        
        for flag in self.flags:
            flag.enabled = new_state
        
        self.update_display()
        self.notify(f"All flags {'enabled' if new_state else 'disabled'}!")

    def action_help(self) -> None:
        """Show help information."""
        help_text = """
        Keybindings:
        - q: Quit
        - s: Save changes
        - r: Reload from file
        - t: Toggle all flags
        - ?: Show this help
        
        Click checkboxes to enable/disable individual flags.
        """
        self.notify(help_text)


def main():
    """Run the config editor."""
    import sys
    
    filename = sys.argv[1] if len(sys.argv) > 1 else "meson.build"
    
    if not sys.path or filename == "--help":
        print("Usage: python vfconfig.py [meson.build]")
        return
    
    try:
        app = MesonConfigEditor(filename)
        app.run()
    except Exception as e:
        print(f"Error: {e}")


if __name__ == "__main__":
    main()
EOF

echo "Fixed vfconfig.py created as vfconfig_fixed.py"

Length of output: 108


🏁 Script executed:

#!/bin/bash
# Show the key differences and improvements
echo "=== KEY FIXES MADE ==="
echo ""
echo "1. TOGGLE LOGIC FIX:"
echo "   - Fixed generate_updated_content() to properly handle enable/disable states"
echo "   - Now correctly removes/adds # based on flag.enabled state"
echo ""
echo "2. INITIAL STATE PARSING FIX:" 
echo "   - Fixed parse_config_flags() to correctly detect if a flag is currently enabled"
echo "   - enabled = not line.strip().startswith('#') properly detects commented lines"
echo ""
echo "3. UI SPACING FIX:"
echo "   - Reduced .flag-container height from auto to 1"
echo "   - Removed excessive margins and padding"
echo "   - Compact horizontal layout for checkboxes and labels"
echo ""
echo "4. ADDITIONAL IMPROVEMENTS:"
echo "   - Better error handling"
echo "   - Improved regex for flag parsing"
echo "   - Proper indentation preservation when toggling"
echo ""
echo "To use the fixed version:"
echo "cp vfconfig_fixed.py vfconfig.py"

Length of output: 1715


🏁 Script executed:

cp vfconfig_fixed.py vfconfig.py

Length of output: 34


@assembler-0, I've successfully identified and fixed all the issues you mentioned in the vfconfig.py script:

Issues Fixed:

1. Toggle Logic Bug ❌➡️✅

Problem: The original generate_updated_content() was using a complex regex but always adding # regardless of the toggle state.

Fix: Simplified logic that:

  • Enables flags: Removes # and whitespace when flag.enabled = True
  • Disables flags: Adds # prefix when flag.enabled = False

2. Initial State Detection Bug ❌➡️✅

Problem: The parsing logic wasn't correctly detecting if flags were currently enabled or disabled when loading the file.

Fix: Changed to enabled = not line.strip().startswith('#') which properly detects commented (disabled) lines.

3. Excessive UI Spacing ❌➡️✅

Problem: The CSS was causing huge gaps between flag options, making the interface unusable.

Fix:

  • Reduced .flag-container height to 1 (was auto)
  • Removed excessive margins and padding
  • Created compact horizontal layout

4. Additional Improvements:

  • Better regex pattern for flag detection
  • Proper indentation preservation when toggling
  • Simplified codebase (removed complexity)
  • Enhanced error handling

The Fix Has Been Applied ✅

I've already replaced your vfconfig.py with the fixed version. The script should now:

  • Show correct initial state when opened
  • Toggle flags properly when you click checkboxes
  • Have compact, usable spacing between options
  • Save changes correctly to meson.build

You can test it by running:

python vfconfig.py

The interface should now be much more user-friendly with proper toggle functionality and compact layout!


🧠 Learnings used
Learnt from: assembler-0
PR: assembler-0/VoidFrame#103
File: README.md:9-9
Timestamp: 2025-09-01T01:10:22.088Z
Learning: VoidFrame's interrupt handlers in arch/x86_64/interrupts/Interrupts.asm only save basic GPRs and segment registers, missing critical registers for deep fault tracing: control registers (CR0/CR2/CR3/CR4), SIMD state (XMM/YMM/ZMM), debug registers (DR0-DR7), and extended FPU state. The CPU initialization code enables SSE/AVX/XSAVE features but interrupt handlers don't preserve this extended state. Enhanced fault tracing requires selective extended state saving for critical exceptions (ISR 6, 8, 13, 14) while keeping lightweight handling for regular interrupts.

Learnt from: assembler-0
PR: assembler-0/VoidFrame#79
File: drivers/PCI/PCI.c:154-154
Timestamp: 2025-08-13T07:26:56.892Z
Learning: VoidFrame kernel uses direct interrupt dispatch in arch/x86_64/interrupts/Interrupts.c rather than RegisterInterruptHandler pattern. Hardware interrupts are handled in switch cases by interrupt number (32+ for IRQs), with proper PIC EOI handling required.

Learnt from: assembler-0
PR: assembler-0/VoidFrame#2
File: Kernel/Syscall.c:44-44
Timestamp: 2025-07-08T00:36:50.297Z
Learning: In IdtSetGate function calls, the parameters are: (interrupt_vector, handler_address, selector, flags). The interrupt vector (like 0x80) is the first argument, and the selector (like 0x08 for kernel code segment) is the third argument.

@assembler-0 assembler-0 merged commit d84bfe7 into main Sep 1, 2025
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant