Skip to content

Conversation

assembler-0
Copy link
Owner

@assembler-0 assembler-0 commented Jul 15, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a kernel heap memory allocator with functions for allocation, reallocation, and freeing of memory.
    • Added new functions for managing CPU interrupt flags and safer spinlock operations.
    • Added standard definitions for size types and NULL.
  • Improvements

    • Enhanced interrupt safety by updating spinlock usage throughout memory and process management.
    • Improved synchronization in process scheduling and memory allocation to prevent race conditions.
    • Updated the timer frequency for improved system timing.
  • Other Changes

    • Updated build configuration to include the new kernel heap source file.
    • Minor documentation and formatting enhancements.

Copy link

coderabbitai bot commented Jul 15, 2025

Walkthrough

This update introduces a kernel heap memory allocator with supporting headers and integrates it into the kernel initialization sequence. It also refactors locking in memory, virtual memory, and process management to use interrupt-safe spinlocks, and adds low-level interrupt flag manipulation utilities. Minor changes include adjusting PIT frequency and updating interrupt and standard type handling.

Changes

Files/Groups Change Summary
arch/x86_64/interrupts/Interrupts.c Keyboard interrupt (33) handled like timer; EOI comment added; minor formatting fix in page fault handling.
drivers/Pic.h PIT_FREQUENCY_HZ macro changed from 1000 to 200.
include/Io.h Added irq_flags_t typedef and inline functions for saving/restoring IRQ flags, disabling/enabling interrupts.
include/stddef.h New header: defines size_t as uint64_t and NULL as ((void*)0).
kernel/atomic/Spinlock.h Added SpinLockIrqSave and SpinUnlockIrqRestore for interrupt-safe spinlocks; includes Io.h.
kernel/core/Kernel.c Includes KernelHeap.h and calls KernelHeapInit() in KernelMain.
kernel/memory/KernelHeap.c, kernel/memory/KernelHeap.h New kernel heap allocator: init, malloc, calloc, realloc, free; thread-safe with spinlocks.
kernel/memory/Memory.c Locking in AllocPage/FreePage switched to SpinLockIrqSave/SpinUnlockIrqRestore; commented-out locks removed from helpers; print on init success.
kernel/memory/VMem.c All locking switched to interrupt-safe spinlock variants in VMemMap, VMemAlloc, VMemFree.
kernel/process/Process.c Scheduler/process management functions now use interrupt-safe scheduler_lock spinlock for critical sections.
meson.build Adds KernelHeap.c to kernel memory sources.

Sequence Diagram(s)

sequenceDiagram
    participant KernelMain
    participant VMem
    participant KernelHeap

    KernelMain->>VMem: VMemInit()
    KernelMain->>KernelHeap: KernelHeapInit()
    KernelMain->>...: Continue kernel startup
Loading
sequenceDiagram
    participant Allocator
    participant Spinlock
    participant VMem

    Allocator->>Spinlock: SpinLockIrqSave(&heap_lock)
    Allocator->>VMem: VMemAlloc(size)
    VMem-->>Allocator: pointer
    Allocator->>Spinlock: SpinUnlockIrqRestore(&heap_lock, flags)
    Allocator-->>Caller: user pointer
Loading
sequenceDiagram
    participant Process
    participant Spinlock

    Process->>Spinlock: SpinLockIrqSave(&scheduler_lock)
    Process->>Process: Critical section (create/terminate/schedule)
    Process->>Spinlock: SpinUnlockIrqRestore(&scheduler_lock, flags)
Loading

Possibly related PRs

  • Cracked #17: Also modifies the interrupt handler, specifically removing debug prints and a commented EOI line, related to interrupt handling logic.

Poem

In the warren of memory, a heap now appears,
With locks that save flags, so no bunny fears.
The scheduler’s guarded, interrupts kept at bay,
While malloc and friends can now safely play.
🐇 Hop, spin, and allocate—
Kernel dreams never abate!

✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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: 3

🔭 Outside diff range comments (2)
kernel/memory/VMem.c (1)

380-383: Inconsistent spinlock usage in VMemGetStats.

This function still uses the basic SpinLock/SpinUnlock pattern while other functions have been updated to use interrupt-safe variants. For consistency and proper interrupt safety, this should also be updated.

-    SpinLock(&vmem_lock);
+    irq_flags_t flags = SpinLockIrqSave(&vmem_lock);
     if (used_pages) *used_pages = kernel_space.used_pages;
     if (total_mapped) *total_mapped = kernel_space.total_mapped;
-    SpinUnlock(&vmem_lock);
+    SpinUnlockIrqRestore(&vmem_lock, flags);
kernel/process/Process.c (1)

115-115: Fix typo in error message.

-        PANIC("Termination queu1e overflow");
+        PANIC("Termination queue overflow");
🧹 Nitpick comments (3)
arch/x86_64/interrupts/Interrupts.c (1)

109-109: Remove duplicate comment.

The comment "// The C-level interrupt handler" is duplicated and appears to be leftover from editing.

-// The C-level interrupt handler
kernel/memory/KernelHeap.h (1)

1-13: Good header structure with naming suggestions.

The header is well-structured with proper include guards and standard includes. However, consider these improvements:

  1. Naming consistency: KernelMemoryAlloc vs KernelFree - consider KernelAlloc for consistency
  2. Documentation: The purpose of KernelCallLocation and KernelRealLocation is unclear from their names

Consider adding brief documentation comments:

+// Initialize the kernel heap
 void KernelHeapInit();
+// Allocate memory block of specified size
 void* KernelMemoryAlloc(size_t size);
+// Purpose unclear - consider renaming or documenting
 void* KernelCallLocation(size_t num, size_t size);
+// Purpose unclear - consider renaming or documenting  
 void* KernelRealLocation(void* ptr, size_t size);
+// Free previously allocated memory block
 void KernelFree(void* ptr);
kernel/memory/KernelHeap.c (1)

57-57: Consider renaming functions for clarity.

The names KernelCallLocation and KernelRealLocation are confusing. Consider using more standard names:

  • KernelCallLocationKernelCalloc (allocates zeroed memory like calloc)
  • KernelRealLocationKernelRealloc (reallocates memory like realloc)

Also applies to: 66-66

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30b2276 and 8933c0e.

📒 Files selected for processing (12)
  • arch/x86_64/interrupts/Interrupts.c (3 hunks)
  • drivers/Pic.h (1 hunks)
  • include/Io.h (1 hunks)
  • include/stddef.h (1 hunks)
  • kernel/atomic/Spinlock.h (2 hunks)
  • kernel/core/Kernel.c (2 hunks)
  • kernel/memory/KernelHeap.c (1 hunks)
  • kernel/memory/KernelHeap.h (1 hunks)
  • kernel/memory/Memory.c (1 hunks)
  • kernel/memory/VMem.c (7 hunks)
  • kernel/process/Process.c (13 hunks)
  • meson.build (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
arch/x86_64/interrupts/Interrupts.c (1)
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.
include/Io.h (1)
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.
🧬 Code Graph Analysis (5)
kernel/core/Kernel.c (2)
kernel/memory/KernelHeap.h (1)
  • KernelHeapInit (7-7)
kernel/memory/KernelHeap.c (1)
  • KernelHeapInit (19-23)
kernel/memory/VMem.c (1)
kernel/atomic/Spinlock.h (4)
  • SpinLockIrqSave (19-26)
  • SpinLockIrqSave (19-19)
  • SpinUnlockIrqRestore (28-31)
  • SpinUnlockIrqRestore (28-28)
kernel/memory/Memory.c (5)
kernel/core/Kernel.c (1)
  • PrintKernelSuccess (158-162)
kernel/core/Kernel.h (1)
  • PrintKernelSuccess (15-15)
kernel/memory/Memory.h (2)
  • AllocPage (10-10)
  • FreePage (11-11)
kernel/atomic/Spinlock.h (4)
  • SpinLockIrqSave (19-26)
  • SpinLockIrqSave (19-19)
  • SpinUnlockIrqRestore (28-31)
  • SpinUnlockIrqRestore (28-28)
kernel/core/Panic.h (1)
  • Panic (11-11)
kernel/atomic/Spinlock.h (1)
include/Io.h (6)
  • save_irq_flags (18-22)
  • save_irq_flags (18-18)
  • cli (28-30)
  • cli (28-28)
  • restore_irq_flags (24-26)
  • restore_irq_flags (24-24)
kernel/memory/KernelHeap.c (4)
kernel/memory/KernelHeap.h (5)
  • KernelHeapInit (7-7)
  • KernelMemoryAlloc (8-8)
  • KernelCallLocation (9-9)
  • KernelRealLocation (10-10)
  • KernelFree (11-11)
kernel/core/Kernel.c (4)
  • PrintKernelSuccess (158-162)
  • PrintKernelError (164-168)
  • PrintKernelInt (203-227)
  • PrintKernel (143-155)
kernel/atomic/Spinlock.h (4)
  • SpinLockIrqSave (19-26)
  • SpinLockIrqSave (19-19)
  • SpinUnlockIrqRestore (28-31)
  • SpinUnlockIrqRestore (28-28)
kernel/memory/VMem.c (2)
  • VMemAlloc (174-222)
  • VMemFree (224-273)
🔇 Additional comments (24)
drivers/Pic.h (1)

4-4: Verify scheduler timing and tick-based constants after PIT frequency change

The PIT rate was reduced from 1000 Hz to 200 Hz (1 ms → 5 ms per tick). This 5× coarser granularity affects all tick-based logic—please review and adjust as needed:

• kernel/process/Process.h
– QUANTUM_BASE (10 ticks → now 50 ms quantum)
– BOOST_INTERVAL (100 ticks → now 500 ms boost interval)
• kernel/process/Process.c
– GetCurrentProcess() security scan interval (every 100 ticks → 500 ms)
– FastSchedule() tick_counter increments and quantum_remaining logic
• arch/x86_64/interrupts/Interrupts.c
– tick_count and FastSchedule called on IRQ0 (timer interrupt)
• drivers/Pic.h & drivers/Pic.c
– PIT_FREQUENCY_HZ divisor use (1193180 / 200 vs. 1193180 / 1000)

Ensure scheduler responsiveness, timeouts, and any timing-sensitive operations still meet design requirements.

include/stddef.h (1)

1-13: LGTM! Standard definitions header is well-implemented.

The header correctly provides kernel-appropriate standard definitions:

  • size_t as uint64_t is suitable for 64-bit kernel architecture
  • NULL definition with proper guard prevents redefinition issues
  • Header guard follows standard conventions

The intentional #undef size_t before redefinition ensures consistent kernel-wide type usage.

include/Io.h (1)

16-35: LGTM! Interrupt flag management functions are correctly implemented.

The x86_64 assembly implementation is accurate:

  • save_irq_flags() uses pushfq/popq to save the 64-bit flags register
  • restore_irq_flags() uses pushq/popfq to restore flags
  • cli() and sti() provide standard interrupt control
  • volatile keyword prevents unwanted compiler optimizations
  • static inline ensures optimal performance

These functions provide the essential primitives for interrupt-safe spinlock implementations.

meson.build (1)

69-69: LGTM! Build system integration is correct.

The kernel heap source file is properly added to the build configuration alongside other memory management components.

kernel/core/Kernel.c (2)

17-17: LGTM! Header inclusion is properly placed.

The KernelHeap.h header is correctly included with other kernel memory management headers.


394-394: LGTM! Kernel heap initialization is correctly positioned.

The KernelHeapInit() call is properly placed after VMemInit() in the kernel startup sequence. This ensures the virtual memory subsystem is initialized before the heap allocator, which is the correct dependency order.

Based on the current implementation, the function performs minimal initialization and primarily serves as a initialization checkpoint.

arch/x86_64/interrupts/Interrupts.c (1)

64-64: Good addition of clarifying comment.

The comment explaining the EOI (End Of Interrupt) operation improves code readability.

kernel/memory/VMem.c (3)

119-159: Excellent improvement to interrupt-safe locking.

The systematic replacement of basic spinlocks with interrupt-safe variants in VMemMap properly prevents race conditions and deadlocks that could occur if interrupts fired during critical sections. The pattern of saving flags on lock acquisition and restoring them on release is correctly implemented.


179-217: Proper interrupt-safe locking implementation in VMemAlloc.

The function correctly uses interrupt-safe spinlocks and properly handles the locking pattern around critical sections. The approach of releasing the lock before calling VMemMap (which has its own locking) prevents deadlocks.


240-268: Good interrupt-safe locking in VMemFree.

The function properly implements interrupt-safe spinlocks with correct flag saving/restoring. The lock is appropriately released before calling FreePage to avoid potential deadlocks.

kernel/atomic/Spinlock.h (2)

5-5: Appropriate dependency addition.

Adding #include "Io.h" is necessary for the interrupt flag management functions used in the new spinlock variants.


18-31: Excellent implementation of interrupt-safe spinlocks.

The implementation correctly follows the standard pattern:

  1. Save current interrupt flags
  2. Disable interrupts
  3. Acquire the spinlock
  4. Return saved flags for later restoration
  5. Release lock and restore interrupt flags

This prevents race conditions and deadlocks that could occur if interrupts fired during critical sections. The use of __builtin_ia32_pause() for busy-waiting is appropriate for x86_64 architecture.

kernel/memory/Memory.c (3)

143-143: Good addition of initialization success message.

The success message provides valuable feedback about physical memory manager initialization, consistent with logging practices used elsewhere in the kernel.


149-161: Proper interrupt-safe locking in AllocPage.

The function correctly implements interrupt-safe spinlocks, saving flags on entry and restoring them on all exit paths. The pattern ensures atomicity during page allocation and prevents race conditions.


165-184: Correct interrupt-safe locking in FreePage.

The function properly uses interrupt-safe spinlocks with consistent flag saving/restoring on all exit paths, including error conditions. This ensures proper synchronization during page deallocation.

kernel/process/Process.c (6)

9-10: LGTM!

The addition of these headers is appropriate for the new interrupt-safe spinlock functionality.


35-35: LGTM!

The scheduler lock is correctly declared as volatile int for use with atomic spinlock operations.


161-249: Spinlock usage is correct and comprehensive.

The interrupt-safe spinlock properly protects all critical sections in the termination process, with correct release on all exit paths.


498-587: Proper scheduler synchronization implemented.

The interrupt-safe spinlock correctly protects the entire scheduling operation, ensuring atomicity during context switches.


678-768: Process creation properly synchronized.

The spinlock correctly protects the entire process creation operation, including slot allocation and initialization.


776-825: Cleanup operations properly synchronized.

The spinlock ensures atomic cleanup of terminated processes, preventing race conditions during resource deallocation.

kernel/memory/KernelHeap.c (3)

1-23: Basic heap structure looks good.

The simple page-based allocator with header metadata is appropriate for initial implementation.


25-55: Memory allocation implementation is correct.

The function properly handles zero-size requests, adds header overhead, and provides appropriate error logging.


98-115: Memory free implementation is correct.

The function properly handles NULL pointers and correctly calculates the total size to free including the header.

Comment on lines +60 to 66
if (regs->interrupt_number == 32 || regs->interrupt_number == 33) { // Force ignore keyboard interrupt
tick_count++;
// FastDisplayTicks(tick_count);
FastSchedule(regs);
outb(0x20, 0x20);
outb(0x20, 0x20); // EOI to master PIC
return;
}
Copy link

@coderabbitai coderabbitai bot Jul 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider proper keyboard interrupt handling instead of treating it as a timer interrupt.

Treating keyboard interrupt (33) the same as timer interrupt (32) by incrementing tick count and calling the scheduler seems like a workaround. This could lead to:

  • Incorrect tick counting and timing
  • Unnecessary scheduler invocations on keyboard input
  • Missing proper keyboard input processing

Consider implementing proper keyboard interrupt handling:

-    if (regs->interrupt_number == 32 || regs->interrupt_number == 33) { // Force ignore keyboard interrupt
+    if (regs->interrupt_number == 32) { // Timer interrupt
         tick_count++;
         // FastDisplayTicks(tick_count);
         FastSchedule(regs);
         outb(0x20, 0x20); // EOI to master PIC
         return;
+    }
+    
+    if (regs->interrupt_number == 33) { // Keyboard interrupt
+        // Handle keyboard input properly
+        HandleKeyboardInterrupt(regs);
+        outb(0x20, 0x20); // EOI to master PIC
+        return;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (regs->interrupt_number == 32 || regs->interrupt_number == 33) { // Force ignore keyboard interrupt
tick_count++;
// FastDisplayTicks(tick_count);
FastSchedule(regs);
outb(0x20, 0x20);
outb(0x20, 0x20); // EOI to master PIC
return;
}
if (regs->interrupt_number == 32) { // Timer interrupt
tick_count++;
// FastDisplayTicks(tick_count);
FastSchedule(regs);
outb(0x20, 0x20); // EOI to master PIC
return;
}
if (regs->interrupt_number == 33) { // Keyboard interrupt
// Handle keyboard input properly
HandleKeyboardInterrupt(regs);
outb(0x20, 0x20); // EOI to master PIC
return;
}
🤖 Prompt for AI Agents
In arch/x86_64/interrupts/Interrupts.c around lines 60 to 66, the keyboard
interrupt (interrupt number 33) is currently handled the same way as the timer
interrupt (32), which is incorrect. To fix this, separate the handling logic for
interrupt 33 by removing the tick_count increment and scheduler call for it, and
instead implement proper keyboard input processing code to handle keyboard
events. Ensure the timer interrupt continues to increment tick_count and call
the scheduler as needed, while the keyboard interrupt processes input and sends
the appropriate EOI to the PIC.

Copy link
Owner Author

Choose a reason for hiding this comment

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

yeah i would love to but the current setup is not suitable, i think tomorrow ill bring back the minimal shell and kbd interrupt, should i?

Copy link

Choose a reason for hiding this comment

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

@assembler-0 That makes perfect sense! Yes, I'd recommend bringing back the minimal shell and keyboard interrupt handling tomorrow. It's a good foundation to have proper interrupt handling in place.

For now, the current workaround is acceptable during development - it's clearly marked with a comment indicating it's temporary. When you do implement the proper keyboard interrupt handling tomorrow, you'll be able to:

  1. Separate the timer and keyboard interrupt logic properly
  2. Have a clean foundation for building more keyboard functionality
  3. Remove the tick count increment from keyboard events

The minimal shell will also give you a nice way to test the keyboard interrupt handling is working correctly. Good prioritization! 👍


🧠 Learnings used
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.

Comment on lines +57 to +64
void* KernelCallLocation(size_t num, size_t size) {
size_t total_size = num * size;
void* ptr = KernelMemoryAlloc(total_size);
if (ptr) {
FastMemset(ptr, 0, total_size);
}
return ptr;
}
Copy link

@coderabbitai coderabbitai bot Jul 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add integer overflow check for allocation size.

The multiplication num * size could overflow, leading to incorrect allocation.

 void* KernelCallLocation(size_t num, size_t size) {
+    // Check for multiplication overflow
+    if (num != 0 && size > SIZE_MAX / num) {
+        return NULL;
+    }
     size_t total_size = num * size;
     void* ptr = KernelMemoryAlloc(total_size);
     if (ptr) {
         FastMemset(ptr, 0, total_size);
     }
     return ptr;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void* KernelCallLocation(size_t num, size_t size) {
size_t total_size = num * size;
void* ptr = KernelMemoryAlloc(total_size);
if (ptr) {
FastMemset(ptr, 0, total_size);
}
return ptr;
}
void* KernelCallLocation(size_t num, size_t size) {
// Check for multiplication overflow
if (num != 0 && size > SIZE_MAX / num) {
return NULL;
}
size_t total_size = num * size;
void* ptr = KernelMemoryAlloc(total_size);
if (ptr) {
FastMemset(ptr, 0, total_size);
}
return ptr;
}
🤖 Prompt for AI Agents
In kernel/memory/KernelHeap.c around lines 57 to 64, add a check to detect
integer overflow when calculating total_size as num multiplied by size. Before
calling KernelMemoryAlloc, verify that the multiplication does not overflow by
ensuring that total_size divided by size equals num. If overflow is detected,
handle it appropriately by returning NULL or an error to prevent incorrect
allocation size.

Copy link
Owner Author

Choose a reason for hiding this comment

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

yeah but idk why when i try to call any function, it kernell panics (page fault), hmm interesting

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

@assembler-0 That's a concerning issue! Page faults when calling functions suggest a systemic problem with memory management or stack handling. Let me help you debug this.

Could you provide more details about:

  1. When exactly does it panic? - During kernel initialization, first function call, or after some operations?
  2. What's the specific function you're trying to call? - Is it KernelCallLocation, KernelMemoryAlloc, or others?
  3. Any pattern? - Does it happen immediately or after certain operations?
  4. Stack trace or register state? - If you have debug output showing where the page fault occurs

This will help pinpoint whether it's a stack corruption, memory mapping issue, or interrupt handling problem.


🏁 Script executed:

#!/bin/bash
# Let's examine the interrupt and stack handling code to identify potential issues
echo "=== Examining interrupt handling code ==="
rg -A 5 -B 5 "page fault|Page fault|PAGE_FAULT" --type c

echo -e "\n=== Checking stack pointer and calling conventions ==="
rg -A 10 -B 5 "rsp|stack.*pointer|call.*function" --type c

echo -e "\n=== Looking for function call patterns and potential issues ==="
rg -A 3 -B 3 "KernelCallLocation|KernelMemoryAlloc" --type c

echo -e "\n=== Examining virtual memory and page mapping ==="
rg -A 5 -B 5 "VMemAlloc|VMemFree|page.*map" --type c

echo -e "\n=== Checking spinlock usage and interrupt handling ==="
rg -A 3 -B 3 "SpinLockIrqSave|SpinUnlockIrqRestore|cli\(\)|sti\(\)" --type c

Length of output: 41464


Based on the search results, I can see several potential causes for your kernel panic issue. The most concerning finding is that no page fault handler code was found in the search results, which is likely the root cause.

Most likely cause: Your system is missing a page fault handler (interrupt #14). When any function call triggers a page fault (which can happen during normal memory allocation, stack operations, or accessing unmapped memory), the kernel has no handler to deal with it, causing a panic.

Immediate questions to help debug:

  1. What's the exact error message/panic screen? - Does it show interrupt number 14 or any specific error codes?
  2. When does it happen? - During kernel initialization, first heap allocation, or when calling specific functions?
  3. Are you calling the new heap functions? - Like KernelMemoryAlloc or KernelCallLocation?

Likely fixes needed:

  1. Add a page fault handler to your interrupt table (interrupt Development #14)
  2. Verify interrupt table setup - Make sure all critical interrupts are properly registered
  3. Check stack alignment - The process creation code shows stack setup, but stack corruption could cause function call failures

Let me know what the script finds and we can pinpoint the exact issue!


🏁 Script executed:

#!/bin/bash
# Let's specifically look for page fault handling and interrupt table setup
echo "=== Searching for page fault handler and interrupt 14 (page fault) ==="
rg -A 10 -B 5 "14|PAGE_FAULT|page_fault_handler|exception.*14" --type c

echo -e "\n=== Examining interrupt table setup ==="
rg -A 10 -B 5 "IdtInstall|IDT|interrupt.*table|exception.*handler" --type c

echo -e "\n=== Checking if interrupt 14 is properly set up ==="
rg -A 5 -B 5 "SetIdtGate.*14|interrupt.*14" --type c

echo -e "\n=== Looking for fault/exception handling infrastructure ==="
rg -A 5 -B 5 "fault.*handler|exception.*handler|InterruptHandler|isr" --type c

echo -e "\n=== Examining the interrupt dispatcher ==="
rg -A 15 -B 5 "interrupt_handler|InterruptDispatcher|irq_handler" --type c

Length of output: 69484


Perfect! Now I can see the exact issue. The problem is NOT missing interrupt registration, but rather missing interrupt handling logic.

🎯 Found the issue! Your interrupt 14 (page fault) IS properly registered in the IDT, but the InterruptHandler function only handles interrupts 32 and 33 (timer and keyboard).

The problem: When a page fault occurs (interrupt 14), it goes to InterruptHandler but there's no specific case for it, so the function just returns without handling the fault, leaving the system in a corrupted state.

Current problematic code:

void InterruptHandler(struct Registers* regs) {
    ASSERT(regs != NULL);
    if (regs->interrupt_number == 32 || regs->interrupt_number == 33) { // Only timer/keyboard
        tick_count++;
        FastSchedule(regs);
        outb(0x20, 0x20); // Send EOI to master PIC
    }
    // ❌ NO HANDLING for interrupt 14 (page fault) or other exceptions!
}

Quick fix: Add page fault handling to your InterruptHandler function:

void InterruptHandler(struct Registers* regs) {
    ASSERT(regs != NULL);
    
    if (regs->interrupt_number == 32 || regs->interrupt_number == 33) {
        tick_count++;
        FastSchedule(regs);
        outb(0x20, 0x20);
    }
    else if (regs->interrupt_number == 14) { // Page fault
        // Handle page fault
        PrintKernelError("Page fault detected!\n");
        PrintKernelError("Error code: ");
        PrintKernelInt(regs->error_code);
        PrintKernelError("\nFaulting address: ");
        // You can get the faulting address from CR2 register
        uint64_t fault_addr;
        asm volatile("mov %%cr2, %0" : "=r"(fault_addr));
        PrintKernelInt(fault_addr);
        PrintKernelError("\nRIP: ");
        PrintKernelInt(regs->rip);
        PrintKernelError("\n");
        
        // For now, panic to see what's happening
        PANIC("Page fault - see details above");
    }
}

This will help you debug exactly what's causing the page fault and where it's happening!


🏁 Script executed:

#!/bin/bash
# Let's look at the current InterruptHandler logic more closely
echo "=== Current InterruptHandler implementation ==="
rg -A 15 -B 5 "InterruptHandler.*struct.*Registers" --type c

echo -e "\n=== Let's see what happens for unhandled interrupts ==="
rg -A 10 -B 5 "interrupt_number.*32|interrupt_number.*33" --type c

echo -e "\n=== Let's check if there are any assembly interrupt files ==="
find . -name "*.asm" -o -name "*.s" | head -10

echo -e "\n=== Check for any page fault specific handling ==="
rg -i "page.*fault|fault.*page" --type c

Length of output: 3444


Perfect! Now I can see the real issue. Your page fault handler IS working correctly! The problem is that you're getting actual page faults when calling functions, which means there's a memory mapping or stack issue.

Let me help you debug this:

The Good News: Your page fault handler is working perfectly! It's correctly detecting and reporting page faults.

The Bad News: You're getting real page faults when calling functions, which means:

  1. Stack corruption - The stack pointer might be invalid or corrupted
  2. Code section not mapped - The function code might not be properly mapped in virtual memory
  3. Memory mapping issues - Virtual memory setup might be incomplete
  4. Function pointer corruption - The function addresses might be invalid

Questions to help debug:

  1. What does the page fault output show?

    • What's the faulting address (CR2 value)?
    • What's the error code?
    • What's the RIP (instruction pointer)?
  2. When exactly does it happen?

    • During kernel initialization?
    • When calling the new heap functions?
    • When calling ANY function?
  3. Are you calling functions from interrupt context?

    • This could cause stack issues

Immediate debugging steps:

  1. Add the missing PrintKernelHex function (if it doesn't exist)
  2. Check if the issue happens during specific function calls
  3. Verify memory mappings are correct

Can you share the exact page fault output you're seeing? That will tell us exactly what's going wrong and where.


🏁 Script executed:

#!/bin/bash
# Let's look at the complete InterruptHandler to see all the diagnostic info
echo "=== Complete InterruptHandler implementation ==="
rg -A 25 -B 5 "PrintKernelError.*PAGE FAULT" --type c

# Let's also check what PrintKernelHex is and if it exists
echo -e "\n=== Check if PrintKernelHex exists ==="
rg -A 5 -B 5 "PrintKernelHex" --type c

# Let's check memory initialization order
echo -e "\n=== Check kernel initialization sequence ==="
rg -A 10 -B 5 "KernelMain|main.*function" --type c

# Let's look at the stack setup in process creation
echo -e "\n=== Check stack setup ==="
rg -A 5 -B 5 "STACK_SIZE|stack.*alloc" --type c

Length of output: 17797


Excellent! Now I can see the complete picture. You have a very comprehensive page fault handler that provides detailed debugging information. The handler shows:

  • Faulting address (CR2 register)
  • Error code with detailed breakdown
  • Whether it's page not present or protection violation
  • Read vs Write operation
  • User vs Supervisor mode

The key question is: What exactly do you see on screen when the kernel panics?

You should be seeing something like:

PAGE FAULT
  Address: 0x[some_address]
  Error Code: 0x[error_code]
  Reason: Page Not Present (or Protection Violation)
  Operation: Read (or Write)
  Mode: Supervisor (or User)

If you're NOT seeing this detailed output, then the page fault is happening before the kernel is fully initialized or during a context where printing doesn't work.

If you ARE seeing this output, then we can debug the exact issue by analyzing:

  1. What's the faulting address? - This tells us what memory location caused the fault
  2. What's the error code? - This tells us the exact type of fault
  3. What's the instruction pointer (RIP)? - This tells us which instruction caused the fault

Can you please share:

  1. The exact text you see on screen when the kernel panics
  2. When does the panic happen? (during boot, after specific operations, etc.)
  3. Are you trying to call any specific functions when it happens?

This will help us pinpoint the exact cause and fix it quickly!


🏁 Script executed:

#!/bin/bash
# Let's check if there are any obvious issues with the heap functions
echo "=== Let's see if there are any function calls that might be causing issues ==="
rg -A 3 -B 3 "KernelMemoryAlloc|KernelCallLocation|KernelHeapInit" --type c

echo -e "\n=== Check if there are any obvious stack or function pointer issues ==="
rg -A 5 -B 5 "entry_point|function.*pointer" --type c

echo -e "\n=== Check for any obvious memory corruption patterns ==="
rg -A 5 -B 5 "corruption|corrupt|invalid.*pointer" --type c

Length of output: 7633


Now I can see the heap functions are being called during kernel initialization. The setup looks correct, but I need to understand exactly what's happening when you get the page fault.

Critical Question: What exactly do you see on screen when the kernel panics?

You should see the detailed page fault output from your handler. If you're not seeing it, that's a clue about when/where the fault is occurring.

Meanwhile, please tell me:

  1. What specific function are you trying to call when it crashes? (e.g., KernelMemoryAlloc, CreateSecureProcess, or something else?)

  2. What exact text appears on screen when the panic happens? Even if it's just partial, that's helpful.

  3. Does the kernel complete initialization before the panic, or does it happen during boot?

  4. Are you adding any new function calls to test the heap, or is this happening with existing code?

Most likely scenarios:

  • Stack overflow - The 4KB process stack might be too small
  • Function called from wrong context - Calling heap functions from interrupt context
  • Virtual memory issue - Functions not properly mapped after heap init
  • Spinlock deadlock - Getting stuck in spinlock during function calls

The detailed page fault info from your handler will tell us exactly what's happening!


🏁 Script executed:

#!/bin/bash
# Let's check what might be called after heap initialization
echo "=== Check what happens after KernelHeapInit in the boot sequence ==="
rg -A 15 -B 5 "KernelHeapInit" --type c

echo -e "\n=== Check if there are any obvious function calls that might be failing ==="
rg -A 5 -B 5 "CreateSecureProcess|SecureKernelIntegritySubsystem" --type c

echo -e "\n=== Check for any assembly function calls that might be problematic ==="
rg -A 5 -B 5 "EnablePagingAndJump|KernelMainHigherHalf" --type c

echo -e "\n=== Let's see if there are any obvious issues with the initialization order ==="
rg -A 20 "KernelMainHigherHalf.*{" --type c

Length of output: 13743


Perfect! Now I can see the exact sequence that's causing the issue. Let me fix that regex and get the complete picture:

🎯 I think I found the issue! Looking at your initialization sequence:

  1. KernelHeapInit() - Called in lower half memory ✅
  2. Virtual memory setup - Creates new page tables ✅
  3. EnablePagingAndJump() - Jumps to higher half virtual memory ✅
  4. KernelMainHigherHalf() - Now running in virtual memory ✅
  5. CreateSecureProcess() - This calls heap functions! ❌

The Problem: The heap functions (like KernelMemoryAlloc) are being called after the virtual memory jump, but the heap's static variables (like kheap_lock) might not be properly mapped in the new virtual memory space!

The kheap_lock static variable in KernelHeap.c was accessible in lower half memory during KernelHeapInit(), but after the virtual memory jump, it might not be properly mapped.

Quick test to confirm:

  1. What exact page fault address do you see? (The CR2 value)
  2. Does it happen immediately when calling CreateSecureProcess()?
  3. Try adding a simple test: Add a call to KernelMemoryAlloc(64) right after KernelHeapInit() (before the virtual memory jump) to see if it works there.

Likely fix: The issue is that the heap's static variables need to be properly mapped in the virtual memory space. The VMemMapKernel() function should map the .bss section which contains static variables like kheap_lock.

Can you share the exact page fault output you see? That will confirm this theory!


🏁 Script executed:

#!/bin/bash
# Fix the regex and check the initialization sequence
echo "=== Check KernelMainHigherHalf initialization sequence ==="
rg -A 20 "KernelMainHigherHalf.*)" --type c

echo -e "\n=== Check what CoreInit does ==="
rg -A 15 -B 5 "CoreInit" --type c

echo -e "\n=== Check the virtual memory mapping details ==="
rg -A 10 -B 5 "VMemMapKernel|\.text.*mapped|\.data.*mapped|\.bss.*mapped" --type c

Length of output: 8901


🎯 FOUND THE ISSUE!

Looking at your initialization sequence, I can see the problem:

  1. Lower half (KernelMain): KernelHeapInit() works fine ✅
  2. Virtual memory jump: EnablePagingAndJump() switches to higher half ✅
  3. Higher half (KernelMainHigherHalf): CoreInit() runs ✅
  4. Missing step: VMemMapKernel() is never called!

The Problem: The VMemMapKernel() function is supposed to map the kernel sections (.text, .data, .bss) in the virtual memory space, but it's never called! Your static variable kheap_lock is in the .bss section and isn't properly mapped in the higher half.

The Fix: Add VMemMapKernel() call after CoreInit() in KernelMainHigherHalf():

void KernelMainHigherHalf(void) {
    CoreInit();
    
    // ADD THIS LINE:
    VMemMapKernel(0, 0); // Parameters are unused according to the code
    
    PrintKernelSuccess("[SYSTEM] Successfully jumped to higher half. Virtual memory is active.\n");
    PrintKernel("[INFO] Creating security manager process...\n");
    uint64_t security_pid = CreateSecureProcess(SecureKernelIntegritySubsystem, PROC_PRIV_SYSTEM);
    // ... rest of the function
}

This will properly map the kernel sections including the .bss section where kheap_lock lives.

Quick verification: Look at the VMemMapKernel() function - it maps:

  • .text section (read-only)
  • .rodata section (read-only)
  • .data section (read-write)
  • .bss section (read-write) ← This is where your kheap_lock static variable is

Without this mapping, when CreateSecureProcess() tries to call heap functions, accessing kheap_lock causes a page fault because it's not mapped in the virtual memory space!

Try adding that one line and the issue should be resolved!


🧬 Code Graph Analysis Results

Relevant snippets from kernel/memory/KernelHeap.h (lines 7-11)

KernelHeapInit()
KernelMemoryAlloc(size_t size)
KernelCallLocation(size_t num, size_t size)
KernelRealLocation(void* ptr, size_t size)
KernelFree(void* ptr)

These are the function declarations corresponding to the implementations in KernelHeap.c.


Relevant snippets from kernel/atomic/Spinlock.h (lines 19-31)

static inline irq_flags_t SpinLockIrqSave(volatile int* lock) {
    irq_flags_t flags = save_irq_flags();
    cli();
    while (__sync_lock_test_and_set(lock, 1)) {
        while (*lock) __builtin_ia32_pause();
    }
    return flags;
}

static inline void SpinUnlockIrqRestore(volatile int* lock, irq_flags_t flags) {
    __sync_lock_release(lock);
    restore_irq_flags(flags);
}

These functions implement spinlock acquisition and release with interrupt flag saving/restoring, used in KernelHeap.c to protect heap operations.


Relevant snippets from kernel/memory/VMem.c (lines 174-222)

void* VMemAlloc(uint64_t size) {
    if (size == 0) return NULL;

    size = PAGE_ALIGN_UP(size);

    irq_flags_t flags = SpinLockIrqSave(&vmem_lock);

    uint64_t vaddr = kernel_space.next_vaddr;

    // Reserve the virtual address space
    kernel_space.next_vaddr += size;

    SpinUnlockIrqRestore(&vmem_lock, flags);

    // Now map pages without holding the lock
    uint64_t allocated_size = 0;
    for (uint64_t offset = 0; offset < size; offset += PAGE_SIZE) {
        void* paddr = AllocPage();
        if (!paddr) {
            // Cleanup on failure
            if (allocated_size > 0) {
                VMemFree((void*)vaddr, allocated_size);
            }
            return NULL;
        }

        int result = VMemMap(vaddr + offset, (uint64_t)paddr, PAGE_WRITABLE);
        if (result != VMEM_SUCCESS) {
            // Free the physical page and cleanup
            FreePage(paddr);
            if (allocated_size > 0) {
                VMemFree((void*)vaddr, allocated_size);
            }
            return NULL;
        }

        allocated_size += PAGE_SIZE;
    }

    // Update tracking
    flags = SpinLockIrqSave(&vmem_lock);
    kernel_space.used_pages += size / PAGE_SIZE;
    kernel_space.total_mapped += size;
    SpinUnlockIrqRestore(&vmem_lock, flags);

    // Zero the allocated memory
    FastMemset((void*)vaddr, 0, size);
    return (void*)vaddr;
}

This function allocates virtual memory pages, maps physical pages, and returns a pointer to the allocated virtual address. It is called by KernelMemoryAlloc in KernelHeap.c.


Relevant snippets from kernel/memory/VMem.c (lines 224-273)

void VMemFree(void* vaddr, uint64_t size) {
    if (!vaddr || size == 0) return;

    size = PAGE_ALIGN_UP(size);
    uint64_t start_vaddr = PAGE_ALIGN_DOWN((uint64_t)vaddr);
    uint64_t num_pages = size / PAGE_SIZE;

    for (uint64_t i = 0; i < num_pages; i++) {
        uint64_t current_vaddr = start_vaddr + (i * PAGE_SIZE);

        // Get physical address first (this has its own locking internally)
        uint64_t paddr = VMemGetPhysAddr(current_vaddr);

        if (paddr == 0) continue; // Not mapped

        // Now acquire lock for modification
        irq_flags_t flags = SpinLockIrqSave(&vmem_lock);
        // Navigate to the Page Table Entry (PTE)
        uint64_t pdp_phys = VMemGetPageTablePhys((uint64_t)kernel_space.pml4, current_vaddr, 0, 0);
        if (!pdp_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }

        uint64_t pd_phys = VMemGetPageTablePhys(pdp_phys, current_vaddr, 1, 0);
        if (!pd_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }

        uint64_t pt_phys = VMemGetPageTablePhys(pd_phys, current_vaddr, 2, 0);
        if (!pt_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }

        // Get virtual address of the page table to modify it
        uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
        int pt_index = (current_vaddr >> PT_SHIFT) & PT_INDEX_MASK;

        // Check if it's actually mapped before proceeding
        if (pt_virt[pt_index] & PAGE_PRESENT) {
            // Clear the entry (unmap)
            pt_virt[pt_index] = 0;

            // Flush the TLB for this specific address
            VMemFlushTLBSingle(current_vaddr);

            // Update stats
            kernel_space.used_pages--;
            kernel_space.total_mapped -= PAGE_SIZE;
        }

        SpinUnlockIrqRestore(&vmem_lock, flags);

        // Free physical page outside the lock
        FreePage((void*)paddr);
    }
}

This function frees virtual memory pages by unmapping them and releasing physical pages. It is called by KernelFree in KernelHeap.c.


Relevant snippets from kernel/core/Kernel.c (lines 143-155, 158-168, 203-227)

void PrintKernel(const char* str) {
    if (!str) return;
    SpinLock(&lock);
    // Cache the original color
    const uint8_t original_color = console.color;

    for (const char* p = str; *p; p++) {
        ConsolePutchar(*p);
    }

    console.color = original_color;
    SpinUnlock(&lock);
}

void PrintKernelSuccess(const char* str) {
    ConsoleSetColor(VGA_COLOR_SUCCESS);
    PrintKernel(str);
    ConsoleSetColor(VGA_COLOR_DEFAULT);
}

void PrintKernelError(const char* str) {
    ConsoleSetColor(VGA_COLOR_ERROR);
    PrintKernel(str);
    ConsoleSetColor(VGA_COLOR_DEFAULT);
}

void PrintKernelInt(int64_t num) {
    char buffer[21]; // Max digits for 64-bit signed integer + sign + null

    if (num == 0) {
        PrintKernel("0");
        return;
    }

    bool negative = num < 0;
    if (negative) num = -num;

    int pos = 20;
    buffer[pos--] = '\0';

    while (num > 0 && pos >= 0) {
        buffer[pos--] = '0' + (num % 10);
        num /= 10;
    }

    if (negative && pos >= 0) {
        buffer[pos--] = '-';
    }

    PrintKernel(&buffer[pos + 1]);
}

These functions handle kernel printing with color and locking, used for debug/error messages in KernelHeap.c.


These snippets provide context on:

  • How kernel heap memory is allocated and freed (KernelMemoryAlloc, KernelFree).
  • How virtual memory pages are allocated and mapped (VMemAlloc) and freed/unmapped (VMemFree).
  • The spinlock mechanism protecting heap operations.
  • Kernel printing functions used for error reporting.

This context is relevant to understanding why calling functions might cause a kernel panic (page fault) if memory allocation or mapping fails or is corrupted.

Comment on lines +66 to +96
void* KernelRealLocation(void* ptr, size_t size) {
if (ptr == NULL) {
return KernelMemoryAlloc(size);
}
if (size == 0) {
KernelFree(ptr);
return NULL;
}

irq_flags_t flags = SpinLockIrqSave(&kheap_lock);

// Get the original header and size
HeapBlockHeader* old_header = (HeapBlockHeader*)((uint8_t*)ptr - sizeof(HeapBlockHeader));
size_t old_size = old_header->size;

// Allocate new memory
void* new_ptr = KernelMemoryAlloc(size);
if (new_ptr) {
// Copy data from old to new, up to the minimum of old_size and new_size
FastMemcpy(new_ptr, ptr, (old_size < size) ? old_size : size);
// Free the old memory block
KernelFree(ptr);
} else {
PrintKernelError("[ERROR] KernelRealLocation: Failed to reallocate ");
PrintKernelInt(size);
PrintKernel(" bytes.\n");
}

SpinUnlockIrqRestore(&kheap_lock, flags);
return new_ptr;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Deadlock in reallocation function.

The function holds kheap_lock while calling KernelMemoryAlloc and KernelFree, which also acquire the same lock, causing a deadlock.

 void* KernelRealLocation(void* ptr, size_t size) {
     if (ptr == NULL) {
         return KernelMemoryAlloc(size);
     }
     if (size == 0) {
         KernelFree(ptr);
         return NULL;
     }

     irq_flags_t flags = SpinLockIrqSave(&kheap_lock);

     // Get the original header and size
     HeapBlockHeader* old_header = (HeapBlockHeader*)((uint8_t*)ptr - sizeof(HeapBlockHeader));
     size_t old_size = old_header->size;

+    SpinUnlockIrqRestore(&kheap_lock, flags);
+
     // Allocate new memory
     void* new_ptr = KernelMemoryAlloc(size);
     if (new_ptr) {
         // Copy data from old to new, up to the minimum of old_size and new_size
         FastMemcpy(new_ptr, ptr, (old_size < size) ? old_size : size);
         // Free the old memory block
         KernelFree(ptr);
     } else {
         PrintKernelError("[ERROR] KernelRealLocation: Failed to reallocate ");
         PrintKernelInt(size);
         PrintKernel(" bytes.\n");
     }

-    SpinUnlockIrqRestore(&kheap_lock, flags);
     return new_ptr;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void* KernelRealLocation(void* ptr, size_t size) {
if (ptr == NULL) {
return KernelMemoryAlloc(size);
}
if (size == 0) {
KernelFree(ptr);
return NULL;
}
irq_flags_t flags = SpinLockIrqSave(&kheap_lock);
// Get the original header and size
HeapBlockHeader* old_header = (HeapBlockHeader*)((uint8_t*)ptr - sizeof(HeapBlockHeader));
size_t old_size = old_header->size;
// Allocate new memory
void* new_ptr = KernelMemoryAlloc(size);
if (new_ptr) {
// Copy data from old to new, up to the minimum of old_size and new_size
FastMemcpy(new_ptr, ptr, (old_size < size) ? old_size : size);
// Free the old memory block
KernelFree(ptr);
} else {
PrintKernelError("[ERROR] KernelRealLocation: Failed to reallocate ");
PrintKernelInt(size);
PrintKernel(" bytes.\n");
}
SpinUnlockIrqRestore(&kheap_lock, flags);
return new_ptr;
}
void* KernelRealLocation(void* ptr, size_t size) {
if (ptr == NULL) {
return KernelMemoryAlloc(size);
}
if (size == 0) {
KernelFree(ptr);
return NULL;
}
irq_flags_t flags = SpinLockIrqSave(&kheap_lock);
// Get the original header and size
HeapBlockHeader* old_header = (HeapBlockHeader*)((uint8_t*)ptr - sizeof(HeapBlockHeader));
size_t old_size = old_header->size;
// Release lock before calling alloc/free to avoid deadlock
SpinUnlockIrqRestore(&kheap_lock, flags);
// Allocate new memory
void* new_ptr = KernelMemoryAlloc(size);
if (new_ptr) {
// Copy data from old to new, up to the minimum of old_size and new_size
FastMemcpy(new_ptr, ptr, (old_size < size) ? old_size : size);
// Free the old memory block
KernelFree(ptr);
} else {
PrintKernelError("[ERROR] KernelRealLocation: Failed to reallocate ");
PrintKernelInt(size);
PrintKernel(" bytes.\n");
}
return new_ptr;
}
🤖 Prompt for AI Agents
In kernel/memory/KernelHeap.c around lines 66 to 96, the function
KernelRealLocation holds the kheap_lock while calling KernelMemoryAlloc and
KernelFree, which themselves acquire the same lock, causing a deadlock. To fix
this, restructure the function to release the lock before calling
KernelMemoryAlloc and KernelFree, and only acquire the lock when accessing or
modifying shared data structures that require synchronization. This avoids
nested locking and prevents deadlocks.

@assembler-0 assembler-0 merged commit 964ead4 into main Jul 16, 2025
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Jul 16, 2025
This was referenced Aug 11, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 2, 2025
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