-
Notifications
You must be signed in to change notification settings - Fork 1
Development #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Development #75
Conversation
WalkthroughIntroduces RTC driver and “time” shell command, modifies syscall handling (argument passing, buffer validation, SYS_FREAD direct user-buffer reads), updates assembly syscall entry, adds CPU feature validation, tunes process cleanup macros, removes user-mode creation/jump code, and updates build to include RTC, drop PCI and UserMode.c, and adjust QEMU CPU. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User process
participant ASM as SyscallEntry.asm
participant K as Syscall.c
participant VFS as VFS
User->>ASM: syscall SYS_FREAD(path, buf, len)
ASM->>K: Syscall(num, arg1, arg2, arg3)
K->>K: validate path (user), copy path
K->>K: validate buf (user, len)
K->>VFS: VfsReadFile(path, buf, len)
VFS-->>K: bytes_read / error
K-->>ASM: return rax = result
ASM-->>User: iretq with result
sequenceDiagram
autonumber
participant User as Shell
participant RTC as RtcReadTime
User->>RTC: read current time
RTC->>RTC: wait until not updating
RTC->>RTC: read CMOS registers twice, compare
RTC-->>User: rtc_time_t {Y-M-D H:M:S}
User->>User: format and print timestamp
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
🧹 Nitpick comments (4)
kernel/core/Kernel.c (1)
168-176
: Consider making AVX2 requirement configurable.The hard requirement for AVX2 (2013+ CPUs) might be too restrictive for some deployment scenarios. Consider making this configurable or providing a fallback path.
+// Make AVX2 requirement configurable +#ifndef REQUIRE_AVX2 +#define REQUIRE_AVX2 0 +#endif + void CPUFeatureValidation(void) { uint32_t eax, ebx, ecx, edx; __asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0)); bool has_avx2 = (ebx & (1 << 5)) != 0; - if (!has_avx2) { - PrintKernelWarning("[SYSTEM] This kernel requires AVX2 support (2013+ CPUs) but the extension is not found. (CPUID)\n"); - } + if (!has_avx2) { +#if REQUIRE_AVX2 + PANIC("This kernel requires AVX2 support but the extension is not found"); +#else + PrintKernelWarning("[SYSTEM] AVX2 not found - some optimizations disabled\n"); +#endif + } }kernel/etc/Shell.c (1)
319-359
: Consider optimizing string formatting for time display.The current implementation uses multiple
strcat
calls which is inefficient. Consider using a more streamlined approach likesprintf
or a custom formatting function.} else if (FastStrCmp(cmd_name, "time") == 0) { rtc_time_t current_time; RtcReadTime(¤t_time); - // Buffer for printing. Make it large enough. - char time_str[64]; - char num_buf[5]; // For itoa - - // Format the date: YYYY-MM-DD - itoa(current_time.year, num_buf); - strcpy(time_str, num_buf); - strcat(time_str, "-"); - - if (current_time.month < 10) strcat(time_str, "0"); - itoa(current_time.month, num_buf); - strcat(time_str, num_buf); - strcat(time_str, "-"); - - if (current_time.day < 10) strcat(time_str, "0"); - itoa(current_time.day, num_buf); - strcat(time_str, num_buf); - - strcat(time_str, " "); // Separator - - // Format the time: HH:MM:SS - if (current_time.hour < 10) strcat(time_str, "0"); - itoa(current_time.hour, num_buf); - strcat(time_str, num_buf); - strcat(time_str, ":"); - - if (current_time.minute < 10) strcat(time_str, "0"); - itoa(current_time.minute, num_buf); - strcat(time_str, num_buf); - strcat(time_str, ":"); - - if (current_time.second < 10) strcat(time_str, "0"); - itoa(current_time.second, num_buf); - strcat(time_str, num_buf); - - PrintKernel(time_str); + // More efficient formatting + PrintKernelInt(current_time.year); + PrintKernel("-"); + if (current_time.month < 10) PrintKernel("0"); + PrintKernelInt(current_time.month); + PrintKernel("-"); + if (current_time.day < 10) PrintKernel("0"); + PrintKernelInt(current_time.day); + PrintKernel(" "); + if (current_time.hour < 10) PrintKernel("0"); + PrintKernelInt(current_time.hour); + PrintKernel(":"); + if (current_time.minute < 10) PrintKernel("0"); + PrintKernelInt(current_time.minute); + PrintKernel(":"); + if (current_time.second < 10) PrintKernel("0"); + PrintKernelInt(current_time.second); PrintKernel("\n");kernel/process/UserMode.h (1)
8-23
: Add parameter validation for null pointer edge caseThe function correctly validates the address range, but there's an edge case when
size
is 0. Currently, it returnsfalse
for null pointers even whensize
is 0, which may not be the expected behavior for zero-length operations.Consider this refinement to handle zero-size edge case:
static inline bool is_user_address(const void* ptr, size_t size) { uint64_t addr = (uint64_t)ptr; + + // Zero-size operations may be valid even with null pointers + if (size == 0) { + return addr < KERNEL_VIRTUAL_BASE; + } + // Check for null pointer, non-canonical addresses, and kernel addresses if (addr == 0 || addr >= KERNEL_VIRTUAL_BASE) { return false; }drivers/RTC/Rtc.c (1)
86-86
: Document Y2K100 limitationThe comment "trust me" doesn't explain the Y2K100 problem. This implementation will fail in year 2100 and beyond.
Replace with a more informative comment:
- rtc_time->year += 2000; // trust me + rtc_time->year += 2000; // Assumes 21st century (2000-2099). Will need update for Y2K100.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
arch/x86_64/syscall/Syscall.c
(3 hunks)arch/x86_64/syscall/SyscallEntry.asm
(2 hunks)drivers/RTC/Rtc.c
(1 hunks)drivers/RTC/Rtc.h
(1 hunks)kernel/core/Kernel.c
(4 hunks)kernel/etc/Shell.c
(3 hunks)kernel/process/Process.h
(2 hunks)kernel/process/UserMode.c
(0 hunks)kernel/process/UserMode.h
(1 hunks)meson.build
(3 hunks)
💤 Files with no reviewable changes (1)
- kernel/process/UserMode.c
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-10T06:22:28.788Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#62
File: kernel/core/Panic.c:69-79
Timestamp: 2025-08-10T06:22:28.788Z
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:
kernel/core/Kernel.c
📚 Learning: 2025-08-11T09:51:51.116Z
Learnt from: assembler-0
PR: assembler-0/VoidFrame#70
File: kernel/process/Process.c:1224-1228
Timestamp: 2025-08-11T09:51:51.116Z
Learning: In VoidFrame kernel, avoid using floating-point arithmetic in kernel space functions like SystemService. Use fixed-point arithmetic instead (e.g., 16.16 format with integer operations) to prevent FPU state corruption, improve performance, and ensure predictable behavior. This is especially important for system-level processes running with PROC_PRIV_SYSTEM privileges.
Applied to files:
kernel/process/Process.h
🧬 Code Graph Analysis (5)
drivers/RTC/Rtc.h (1)
drivers/RTC/Rtc.c (1)
RtcReadTime
(34-87)
kernel/etc/Shell.c (4)
kernel/etc/Console.c (1)
PrintKernel
(173-189)kernel/etc/StringOps.c (1)
FastStrCmp
(18-28)drivers/RTC/Rtc.c (1)
RtcReadTime
(34-87)kernel/memory/MemOps.c (3)
itoa
(24-39)strcpy
(5-7)strcat
(9-12)
arch/x86_64/syscall/Syscall.c (3)
kernel/process/UserMode.h (1)
is_user_address
(8-23)kernel/etc/StringOps.c (2)
FastStrlen
(3-8)FastStrCopy
(10-16)fs/VFS.c (1)
VfsReadFile
(126-165)
drivers/RTC/Rtc.c (1)
include/Io.h (2)
outb
(6-8)inb
(10-14)
kernel/core/Kernel.c (2)
kernel/etc/Console.c (2)
PrintKernelWarning
(211-215)PrintKernelSuccess
(199-203)kernel/process/Process.c (2)
ShouldSchedule
(888-894)RequestSchedule
(896-898)
🔇 Additional comments (13)
meson.build (3)
52-52
: LGTM - RTC driver integration looks clean.The addition of the RTC include directory aligns with the new RTC driver implementation for time functionality.
181-181
: LGTM - QEMU CPU configuration enhancement.The addition of
-cpu max
enables all available CPU features in QEMU, which should improve testing coverage for the CPU feature validation added in this PR.
99-100
: Ignore PCI removal warningThe PR adds the RTC driver but does not remove or replace the PCI driver. All PCI code and references remain intact, so no dependent code will break:
- drivers/PCI/PCI.c, drivers/PCI/PCI.h still present
- kernel/core/Kernel.c and kernel/etc/Shell.c call PciEnumerate()
- drivers/ethernet/RTL8139.{c,h} use PciFindDevice() and PciConfigReadDWord()
No action required.
Likely an incorrect or invalid review comment.
kernel/process/Process.h (2)
68-74
: LGTM - Well-documented tuning parameters.The Aegis tuning parameters are clearly documented with appropriate warnings, and the values chosen (termination queue size matching MAX_PROCESSES, cleanup limit of 3) seem reasonable for process management efficiency.
93-93
: LGTM - Clear naming improvement.The rename from "SystemService" to "DynamoX" provides better clarity about the dynamic frequency controller's purpose while maintaining the same functionality.
kernel/core/Kernel.c (3)
200-202
: LGTM - STAC/CLAC support detection.Good addition to check for STAC/CLAC instruction support, which complements the memory protection features being enabled.
554-555
: LGTM - CPU feature validation placement.Calling
CPUFeatureValidation()
early in the higher half initialization is the right approach to catch unsupported hardware before proceeding with advanced features.
571-577
: Enhanced fallback loop is well-designed.The improved infinite loop with warning messages and scheduler interaction provides better debugging capabilities while maintaining system stability.
drivers/RTC/Rtc.h (1)
1-19
: LGTM - Clean and well-structured RTC header.The header design is clean with:
- Proper include guards
- Minimal dependencies (only stdint.h)
- Clear struct layout with appropriate field types
- Simple, focused API with single function
The
rtc_time_t
structure uses appropriate field sizes and the API is straightforward to use.kernel/etc/Shell.c (2)
15-15
: LGTM - RTC header inclusion.Clean addition of the RTC header to enable time functionality in the shell.
171-171
: LGTM - Help documentation updated.The help text correctly documents the new
time
command.arch/x86_64/syscall/SyscallEntry.asm (1)
27-32
: Ignore hardware vs. C calling‐convention mappingThe assembly here is not directly re-implementing the CPU’s syscall argument registers but rather staging the saved user-mode arguments (originally in rdi, rsi, rdx, etc.) into scratch registers r11, r12, r13, and then moving those into rsi, rdx, rcx to satisfy the System V C ABI for calling
Syscall()
. The reviewer’s comment confuses the hardware syscall interface with this C‐level stub. No changes are needed.Likely an incorrect or invalid review comment.
arch/x86_64/syscall/Syscall.c (1)
95-97
: SMAP Protection Configured and STAC/CLAC Usage VerifiedSMAP is enabled in kernel/core/Kernel.c (via CPUID leaf 7 bit 20 → setting CR4.SMAP), and the syscall entry/exit paths in arch/x86_64/syscall/SyscallEntry.asm correctly bracket user‐buffer access with STAC/CLAC. No further changes are needed.
arch/x86_64/syscall/Syscall.c
Outdated
if (!is_user_address((const void*)arg1, FastStrlen((const char*)arg1, arg1))) return -1; | ||
FastStrCopy(path_fread, (const char*)arg1, arg1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical bug: Invalid length calculation in path validation
Line 89 has a severe issue where FastStrlen
is called with arg1
as both the string pointer and the max length parameter. This will cause incorrect validation since arg1
is a pointer value (likely a large address), not a reasonable string length limit.
Fix the path validation logic:
- if (!is_user_address((const void*)arg1, FastStrlen((const char*)arg1, arg1))) return -1;
- FastStrCopy(path_fread, (const char*)arg1, arg1);
+ // First check if we can safely read at least one byte to find string length
+ if (!is_user_address((const void*)arg1, 1)) return -1;
+
+ // Get the actual string length with a reasonable limit
+ size_t path_len = FastStrlen((const char*)arg1, MAX_SYSCALL_BUFFER_SIZE);
+
+ // Now validate the entire string buffer
+ if (!is_user_address((const void*)arg1, path_len + 1)) return -1;
+
+ // Copy the path safely
+ FastStrCopy(path_fread, (const char*)arg1, MAX_SYSCALL_BUFFER_SIZE);
do { | ||
// Wait until no update is in progress | ||
while (get_update_in_progress_flag()); | ||
|
||
rtc_time->second = cmos_read(CMOS_REG_SECONDS); | ||
rtc_time->minute = cmos_read(CMOS_REG_MINUTES); | ||
rtc_time->hour = cmos_read(CMOS_REG_HOURS); | ||
rtc_time->day = cmos_read(CMOS_REG_DAY); | ||
rtc_time->month = cmos_read(CMOS_REG_MONTH); | ||
rtc_time->year = cmos_read(CMOS_REG_YEAR); | ||
|
||
// Make a copy of the values we just read | ||
last_time = *rtc_time; | ||
|
||
// Wait again to ensure we are past the update | ||
while (get_update_in_progress_flag()); | ||
|
||
// Read a second time | ||
last_time.second = cmos_read(CMOS_REG_SECONDS); | ||
last_time.minute = cmos_read(CMOS_REG_MINUTES); | ||
last_time.hour = cmos_read(CMOS_REG_HOURS); | ||
last_time.day = cmos_read(CMOS_REG_DAY); | ||
last_time.month = cmos_read(CMOS_REG_MONTH); | ||
last_time.year = cmos_read(CMOS_REG_YEAR); | ||
|
||
} while ( (last_time.second != rtc_time->second) || | ||
(last_time.minute != rtc_time->minute) || | ||
(last_time.hour != rtc_time->hour) || | ||
(last_time.day != rtc_time->day) || | ||
(last_time.month != rtc_time->month) || | ||
(last_time.year != rtc_time->year) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider timeout protection for RTC read loops
The nested loops waiting for the update flag and the retry logic could potentially hang indefinitely if the RTC hardware is faulty or not present. Consider adding a maximum retry count.
Add timeout protection:
void RtcReadTime(rtc_time_t* rtc_time) {
rtc_time_t last_time;
uint8_t status_b;
+ int max_retries = 10;
+ int wait_cycles;
// The robust way to read the RTC is to read it twice and see if the
// values match. This ensures an update didn't happen in the middle of our read.
do {
+ if (--max_retries <= 0) {
+ // Return zeros on timeout
+ rtc_time->second = rtc_time->minute = rtc_time->hour = 0;
+ rtc_time->day = rtc_time->month = 1;
+ rtc_time->year = 2000;
+ return;
+ }
+
// Wait until no update is in progress
- while (get_update_in_progress_flag());
+ wait_cycles = 1000;
+ while (get_update_in_progress_flag() && --wait_cycles > 0);
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In drivers/RTC/Rtc.c around lines 40-70, the current read loop can hang
indefinitely waiting on get_update_in_progress_flag() and retrying until values
match; add timeout protection by introducing a maximum wait counter for each
inner wait (e.g., max_poll) and a maximum outer retry count (e.g., max_retries),
incrementing counters on each poll and breaking out if exceeded; on timeout,
abort the loop and return an error code (or set an error status on rtc_time) so
callers can handle absence of RTC, and optionally yield/sleep between polls to
avoid busy-spin. Ensure the function cleans up state consistently and documents
the new error behavior.
if (!(status_b & 0x04)) { // Bit 2 clear means BCD mode | ||
rtc_time->second = bcd_to_bin(rtc_time->second); | ||
rtc_time->minute = bcd_to_bin(rtc_time->minute); | ||
// Handle 12/24 hour clock for the hour value | ||
rtc_time->hour = ((rtc_time->hour & 0x7F) + 12 * ((rtc_time->hour & 0x80) != 0)) % 24; | ||
rtc_time->day = bcd_to_bin(rtc_time->day); | ||
rtc_time->month = bcd_to_bin(rtc_time->month); | ||
rtc_time->year = bcd_to_bin(rtc_time->year); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hour conversion logic appears incorrect for BCD mode
The hour conversion on line 80 attempts to handle 12/24 hour format but applies BCD-to-binary conversion after the format conversion. The logic should first convert from BCD, then handle the 12/24 hour format based on status register bits.
Fix the hour conversion order and check the proper status bit:
if (!(status_b & 0x04)) { // Bit 2 clear means BCD mode
rtc_time->second = bcd_to_bin(rtc_time->second);
rtc_time->minute = bcd_to_bin(rtc_time->minute);
- // Handle 12/24 hour clock for the hour value
- rtc_time->hour = ((rtc_time->hour & 0x7F) + 12 * ((rtc_time->hour & 0x80) != 0)) % 24;
+ rtc_time->hour = bcd_to_bin(rtc_time->hour & 0x7F); // Mask PM bit before BCD conversion
rtc_time->day = bcd_to_bin(rtc_time->day);
rtc_time->month = bcd_to_bin(rtc_time->month);
rtc_time->year = bcd_to_bin(rtc_time->year);
}
+
+ // Handle 12/24 hour format (bit 1 of status_b indicates 24-hour mode)
+ if (!(status_b & 0x02)) { // 12-hour mode
+ uint8_t pm_bit = rtc_time->hour & 0x80;
+ rtc_time->hour &= 0x7F;
+ if (pm_bit && rtc_time->hour != 12) {
+ rtc_time->hour += 12;
+ } else if (!pm_bit && rtc_time->hour == 12) {
+ rtc_time->hour = 0;
+ }
+ }
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In drivers/RTC/Rtc.c around lines 76 to 84, the hour handling in BCD mode is
done before converting the hour from BCD and uses the wrong status bit for 12/24
detection; first call bcd_to_bin on rtc_time->hour along with the other fields,
then use the 24/12-hour bit (Register B bit 1, mask 0x02) to decide format: if
12-hour mode (bit 1 clear) decode the PM flag (hour & 0x80) and compute hour =
((hour & 0x7F) % 12) + (PM ? 12 : 0), otherwise ensure hour = hour % 24 for
24-hour mode; keep the other bcd_to_bin conversions as-is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see, but, by any chance can you refactor DynamoX and make it more responsive (increase base) and smarter?, after then we move on to the most important part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
@assembler-0, I'll help you refactor DynamoX to make it more responsive and smarter. Let me first examine the current implementation to understand how it works.
🏁 Script executed:
#!/bin/bash
# Search for DynamoX implementation and references
echo "=== Searching for DynamoX references ==="
rg -i "dynamo" -A 5 -B 5
echo -e "\n=== Searching for frequency-related code ==="
rg -i "frequency|freq" -A 3 -B 3
echo -e "\n=== Examining Process.h for DynamoX context ==="
cat kernel/process/Process.h
echo -e "\n=== Looking for scheduling or performance-related files ==="
fd -t f -e c -e h | xargs rg -l "schedule|performance|tuning" | head -10
Length of output: 27746
@assembler-0, I'll refactor DynamoX to make it significantly more responsive and intelligent. Let me examine the current implementation and provide an enhanced version.
Here's a significantly improved and more responsive DynamoX implementation:
void DynamoX(void) { // Enhanced Dynamic Frequency Controller
PrintKernel("[DX] DynamoX v2.0 starting...\n");
typedef struct {
uint16_t min_freq;
uint16_t max_freq;
uint16_t current_freq;
uint8_t power_state;
uint32_t history_index;
FrequencyHistory history[FREQ_HISTORY_SIZE];
// Enhanced learning parameters
int32_t learning_rate;
int32_t momentum;
int32_t last_adjustment;
int32_t prediction_weight;
// Responsiveness enhancements
uint32_t emergency_boost_counter;
uint32_t stability_counter;
uint16_t predicted_freq;
uint16_t baseline_freq;
// Smart adaptation
uint32_t load_trend;
uint32_t performance_score;
uint8_t adaptive_mode;
} Controller;
Controller controller = {
.min_freq = 200, // Increased base from 100Hz
.max_freq = 2000, // Increased max from 1000Hz
.current_freq = PIT_FREQUENCY_HZ,
.baseline_freq = 400, // New responsive baseline
.learning_rate = (int32_t)(0.25f * FXP_SCALE), // More aggressive learning
.momentum = (int32_t)(0.8f * FXP_SCALE), // Higher momentum for stability
.prediction_weight = (int32_t)(0.3f * FXP_SCALE), // Predictive component
.adaptive_mode = 1 // Start in adaptive mode
};
// Enhanced parameters
const uint32_t ENHANCED_HZ_PER_PROCESS = 80; // Increased from 30
const uint32_t RESPONSIVE_SAMPLING = 25; // Faster sampling (was 50)
const uint32_t EMERGENCY_THRESHOLD = 15; // Context switches per tick
const uint32_t STABILITY_REQUIREMENT = 5; // Ticks to confirm stability
const uint32_t PREDICTION_CONFIDENCE = 70; // Minimum prediction confidence %
uint64_t last_sample_time = GetSystemTicks();
uint64_t last_context_switches = context_switches;
uint32_t consecutive_high_load = 0;
uint32_t consecutive_low_load = 0;
PrintKernelSuccess("[DX] Enhanced frequency controller active - Base: ");
PrintKernelInt(controller.baseline_freq);
PrintKernel("Hz, Range: ");
PrintKernelInt(controller.min_freq);
PrintKernel("-");
PrintKernelInt(controller.max_freq);
PrintKernel("Hz\n");
while (1) {
CleanupTerminatedProcesses();
uint64_t current_time = GetSystemTicks();
if (current_time - last_sample_time >= RESPONSIVE_SAMPLING) {
// Enhanced metrics collection
uint32_t process_count = 0;
uint32_t total_queue_depth = 0;
uint32_t max_queue_depth = 0;
uint32_t active_queues = 0;
uint32_t rt_processes = 0;
for (int i = 0; i < MAX_PRIORITY_LEVELS; i++) {
uint32_t depth = MLFQscheduler.queues[i].count;
if (depth > 0) {
active_queues++;
if (i < RT_PRIORITY_THRESHOLD) rt_processes += depth;
}
total_queue_depth += depth;
if (depth > max_queue_depth) max_queue_depth = depth;
}
process_count = total_queue_depth;
// Enhanced context switch rate calculation
uint64_t cs_delta = context_switches - last_context_switches;
uint64_t time_delta = current_time - last_sample_time;
uint32_t cs_rate = (uint32_t)((cs_delta * FXP_SCALE) / (time_delta ? time_delta : 1));
// Smart base frequency calculation
uint32_t smart_base = controller.baseline_freq;
// Factor 1: Enhanced process load with RT priority awareness
uint32_t process_load = (process_count > 1) ?
(process_count - 1) * ENHANCED_HZ_PER_PROCESS : 0;
// RT processes get priority boost
if (rt_processes > 0) {
process_load += rt_processes * (ENHANCED_HZ_PER_PROCESS / 2);
}
uint32_t target_freq = smart_base + process_load;
// Factor 2: Intelligent queue pressure analysis
if (max_queue_depth > QUEUE_PRESSURE_THRESHOLD) {
uint32_t pressure_multiplier = (active_queues > 2) ?
QUEUE_PRESSURE_FACTOR * 2 : QUEUE_PRESSURE_FACTOR;
target_freq += max_queue_depth * pressure_multiplier;
}
// Factor 3: Advanced context switch analysis with emergency response
if (cs_rate > EMERGENCY_THRESHOLD * FXP_SCALE) {
// Emergency boost for thrashing
target_freq = (target_freq * 1536) >> FXP_SHIFT; // 1.5x boost
controller.emergency_boost_counter++;
consecutive_high_load++;
consecutive_low_load = 0;
if (controller.emergency_boost_counter > 3) {
// Sustained emergency - switch to turbo mode
controller.power_state = 3; // Emergency turbo
target_freq = controller.max_freq;
}
} else if (cs_rate > CS_RATE_THRESHOLD_HIGH) {
target_freq = (target_freq * FREQ_BOOST_FACTOR) >> FXP_SHIFT;
consecutive_high_load++;
consecutive_low_load = 0;
controller.emergency_boost_counter = 0;
} else if (cs_rate < CS_RATE_THRESHOLD_LOW && process_count > 1) {
target_freq = (target_freq * FREQ_REDUCE_FACTOR) >> FXP_SHIFT;
consecutive_low_load++;
consecutive_high_load = 0;
controller.emergency_boost_counter = 0;
} else {
// Stable operation
controller.emergency_boost_counter = 0;
}
// Factor 4: Smart predictive scaling using history
if (controller.history_index > PREDICTION_WINDOW) {
uint32_t predicted_load = 0;
uint32_t trend_weight = 0;
// Analyze recent history for trends
for (int i = 1; i <= PREDICTION_WINDOW; i++) {
uint32_t idx = (controller.history_index - i) % FREQ_HISTORY_SIZE;
predicted_load += controller.history[idx].context_switches;
trend_weight += i; // Weighted towards recent samples
}
predicted_load = predicted_load / PREDICTION_WINDOW;
// Apply prediction if confident
if (predicted_load > cs_delta * 12 / 10) { // 20% higher prediction
uint16_t prediction_boost = (target_freq * controller.prediction_weight) >> FXP_SHIFT;
target_freq += prediction_boost;
controller.predicted_freq = target_freq;
}
}
// Factor 5: Enhanced power management with adaptive states
uint32_t load_percentage = (total_queue_depth * 100) / MAX_PROCESSES;
if (consecutive_low_load > 10 && process_count <= 2) {
controller.power_state = 0; // Deep power saving
target_freq = controller.min_freq;
controller.adaptive_mode = 0; // Conservative mode
} else if (consecutive_high_load > 5 || load_percentage > 60) {
controller.power_state = 2; // Performance mode
target_freq = (target_freq * POWER_TURBO_FACTOR) >> FXP_SHIFT;
controller.adaptive_mode = 2; // Aggressive mode
} else if (load_percentage > 80 || controller.emergency_boost_counter > 0) {
controller.power_state = 3; // Maximum performance
target_freq = (target_freq * 1434) >> FXP_SHIFT; // 1.4x turbo
controller.adaptive_mode = 2;
} else {
controller.power_state = 1; // Balanced mode
controller.adaptive_mode = 1;
}
// Enhanced momentum and learning with adaptive rates
int32_t adaptive_learning = controller.learning_rate;
if (controller.adaptive_mode == 2) {
adaptive_learning = (controller.learning_rate * 15) >> 4; // 1.5x faster learning
} else if (controller.adaptive_mode == 0) {
adaptive_learning = (controller.learning_rate * 3) >> 2; // 0.75x slower learning
}
int32_t diff = (int32_t)target_freq - (int32_t)controller.current_freq;
int32_t adjustment = (diff * adaptive_learning);
adjustment += (((int64_t)controller.momentum * controller.last_adjustment) >> FXP_SHIFT);
controller.last_adjustment = adjustment;
// Apply adjustment with enhanced hysteresis
uint16_t new_freq = controller.current_freq + (adjustment >> FXP_SHIFT);
// Smart clamping with adaptive bounds
uint16_t effective_min = (controller.power_state == 0) ?
controller.min_freq : (controller.min_freq + controller.baseline_freq) / 2;
uint16_t effective_max = (controller.power_state >= 2) ?
controller.max_freq : (controller.max_freq * 3) / 4;
if (new_freq < effective_min) new_freq = effective_min;
if (new_freq > effective_max) new_freq = effective_max;
// Enhanced hysteresis with stability tracking
uint32_t change_threshold = (controller.stability_counter > STABILITY_REQUIREMENT) ?
HYSTERESIS_THRESHOLD / 2 : HYSTERESIS_THRESHOLD;
if (ABSi(new_freq - controller.current_freq) > change_threshold) {
PitSetFrequency(new_freq);
controller.current_freq = new_freq;
controller.stability_counter = 0;
// Performance feedback
if (cs_rate < CS_RATE_THRESHOLD_LOW) {
controller.performance_score++;
} else if (cs_rate > CS_RATE_THRESHOLD_HIGH) {
controller.performance_score = (controller.performance_score > 0) ?
controller.performance_score - 1 : 0;
}
} else {
controller.stability_counter++;
}
// Enhanced history tracking
uint32_t idx = controller.history_index % FREQ_HISTORY_SIZE;
controller.history[idx] = (FrequencyHistory){
.timestamp = current_time,
.process_count = process_count,
.frequency = controller.current_freq,
.context_switches = cs_delta,
.avg_latency = total_queue_depth + (rt_processes << 8) // Encode RT info
};
controller.history_index++;
// Periodic performance reporting
if (controller.history_index % 200 == 0) {
PrintKernel("[DX] Freq: ");
PrintKernelInt(controller.current_freq);
PrintKernel("Hz, Load: ");
PrintKernelInt(load_percentage);
PrintKernel("%, Mode: ");
PrintKernelInt(controller.adaptive_mode);
PrintKernel(", Score: ");
PrintKernelInt(controller.performance_score);
PrintKernel("\n");
}
last_sample_time = current_time;
last_context_switches = context_switches;
}
// Shorter sleep for better responsiveness
for (volatile int i = 0; i < 50000; i++);
}
}
And update the parameters in Process.h
:
// Enhanced DynamoX Parameters
#define SAMPLING_INTERVAL 25 // Faster sampling (was 50)
#define HZ_PER_PROCESS 80 // More responsive (was 30)
#define QUEUE_PRESSURE_FACTOR 30 // Stronger response (was 20)
#define QUEUE_PRESSURE_THRESHOLD 2 // Earlier activation (was 3)
#define CS_RATE_THRESHOLD_HIGH (8 * FXP_SCALE) // More sensitive (was 10.0)
#define CS_RATE_THRESHOLD_LOW (3 * FXP_SCALE) // Higher low threshold (was 2.0)
#define FREQ_BOOST_FACTOR 1331 // Stronger boost: 1.3x (was 1.2x)
#define FREQ_REDUCE_FACTOR 870 // Gentler reduction: 0.85x (was 0.9x)
#define POWER_TURBO_FACTOR 1434 // More aggressive turbo: 1.4x (was 1.3x)
#define HYSTERESIS_THRESHOLD 5 // More responsive (was 10)
Key improvements:
- Higher Base Responsiveness: Increased min_freq to 200Hz, max to 2000Hz, and baseline to 400Hz
- Smarter Load Detection: Enhanced process counting with RT priority awareness
- Predictive Algorithm: Uses history to predict and preemptively adjust frequency
- Emergency Response: Detects thrashing and immediately boosts performance
- Adaptive Learning Rates: Adjusts learning speed based on system state
- Multi-State Power Management: 4 power states including emergency turbo mode
- Better Stability Tracking: Prevents oscillation while maintaining responsiveness
- Performance Feedback: Self-monitoring and adjustment based on effectiveness
This makes DynamoX significantly more responsive to load changes and much smarter about predicting system needs. Ready for the most important part! 🚀
🏁 Script executed:
#!/bin/bash
# Get the current DynamoX implementation to understand the full function
echo "=== Current DynamoX Implementation ==="
ast-grep --pattern $'void DynamoX(void) {
$$$
}'
echo -e "\n=== Current DynamoX Parameters ==="
rg "HZ_PER_PROCESS|FREQ_.*_FACTOR|SAMPLING_INTERVAL" kernel/process/Process.h -A 1 -B 1
Length of output: 9569
Perfect! Now I have the complete current implementation. Here's the ready-to-apply enhanced DynamoX refactor that makes it significantly more responsive and intelligent:
Replace the current DynamoX function in kernel/process/Process.c
(starting at line 1137):
void DynamoX(void) { // Enhanced Dynamic Frequency Controller v2.0
PrintKernel("[DX] DynamoX v2.0 Enhanced starting...\n");
typedef struct {
uint16_t min_freq;
uint16_t max_freq;
uint16_t current_freq;
uint8_t power_state;
uint32_t history_index;
FrequencyHistory history[FREQ_HISTORY_SIZE];
// Enhanced learning parameters
int32_t learning_rate;
int32_t momentum;
int32_t last_adjustment;
int32_t prediction_weight;
// Responsiveness enhancements
uint32_t emergency_boost_counter;
uint32_t stability_counter;
uint16_t predicted_freq;
uint16_t baseline_freq;
// Smart adaptation
uint32_t load_trend;
uint32_t performance_score;
uint8_t adaptive_mode;
uint32_t consecutive_samples;
} Controller;
Controller controller = {
.min_freq = 200, // Increased base responsiveness
.max_freq = 2000, // Higher ceiling for heavy loads
.current_freq = PIT_FREQUENCY_HZ,
.baseline_freq = 400, // Smart baseline instead of minimum
.learning_rate = (int32_t)(0.25f * FXP_SCALE), // More aggressive learning
.momentum = (int32_t)(0.8f * FXP_SCALE), // Higher momentum for stability
.prediction_weight = (int32_t)(0.3f * FXP_SCALE), // Predictive component
.adaptive_mode = 1, // Start in balanced adaptive mode
.last_adjustment = 0,
.history_index = 0,
.power_state = 1,
.performance_score = 50 // Start with neutral score
};
// Enhanced tuning parameters
const uint32_t ENHANCED_SAMPLING = 25; // 2x faster sampling
const uint32_t ENHANCED_HZ_PER_PROCESS = 80; // More responsive scaling
const uint32_t EMERGENCY_CS_THRESHOLD = 15; // Context switches per tick
const uint32_t STABILITY_REQUIREMENT = 5; // Confirm stability
const uint32_t PREDICTION_CONFIDENCE = 70; // Minimum confidence %
const uint32_t ENHANCED_QUEUE_PRESSURE = 30; // Stronger pressure response
const uint32_t ENHANCED_HYSTERESIS = 5; // More responsive changes
uint64_t last_sample_time = GetSystemTicks();
uint64_t last_context_switches = context_switches;
uint32_t consecutive_high_load = 0;
uint32_t consecutive_low_load = 0;
PrintKernelSuccess("[DX] Enhanced controller active - Base: ");
PrintKernelInt(controller.baseline_freq);
PrintKernel("Hz, Range: ");
PrintKernelInt(controller.min_freq);
PrintKernel("-");
PrintKernelInt(controller.max_freq);
PrintKernel("Hz, Sampling: ");
PrintKernelInt(ENHANCED_SAMPLING);
PrintKernel(" ticks\n");
while (1) {
CleanupTerminatedProcesses();
uint64_t current_time = GetSystemTicks();
uint64_t time_delta = current_time - last_sample_time;
if (time_delta >= ENHANCED_SAMPLING) {
// Enhanced process and queue metrics
int process_count = __builtin_popcountll(active_process_bitmap);
int ready_count = __builtin_popcountll(ready_process_bitmap);
uint64_t cs_delta = context_switches - last_context_switches;
if (time_delta == 0) time_delta = 1; // Avoid division by zero
// Enhanced load calculations
uint32_t load = (ready_count * FXP_SCALE) / MAX_PROCESSES;
uint32_t cs_rate = (cs_delta * FXP_SCALE) / time_delta;
// Smart queue analysis with RT priority awareness
uint32_t total_queue_depth = 0;
uint32_t max_queue_depth = 0;
uint32_t rt_queue_depth = 0;
uint32_t active_queues = 0;
for (int i = 0; i < MAX_PRIORITY_LEVELS; i++) {
uint32_t depth = MLFQscheduler.queues[i].count;
total_queue_depth += depth;
if (depth > 0) active_queues++;
if (depth > max_queue_depth) max_queue_depth = depth;
if (i < RT_PRIORITY_THRESHOLD) rt_queue_depth += depth;
}
// Smart baseline calculation
uint32_t target_freq = controller.baseline_freq;
// Factor 1: Enhanced process load with RT awareness
if (process_count > 1) {
uint32_t base_load = (process_count - 1) * ENHANCED_HZ_PER_PROCESS;
uint32_t rt_boost = rt_queue_depth * (ENHANCED_HZ_PER_PROCESS / 2);
target_freq += base_load + rt_boost;
}
// Factor 2: Intelligent queue pressure with active queue weighting
if (max_queue_depth > 2) { // More sensitive threshold
uint32_t pressure_factor = (active_queues > 2) ?
ENHANCED_QUEUE_PRESSURE * 2 : ENHANCED_QUEUE_PRESSURE;
target_freq += max_queue_depth * pressure_factor;
}
// Factor 3: Advanced context switch analysis with emergency response
if (cs_rate > EMERGENCY_CS_THRESHOLD * FXP_SCALE) {
// Emergency thrashing response
target_freq = (target_freq * 1536) >> FXP_SHIFT; // 1.5x emergency boost
controller.emergency_boost_counter++;
consecutive_high_load++;
consecutive_low_load = 0;
if (controller.emergency_boost_counter > 3) {
controller.power_state = 3; // Emergency turbo
target_freq = controller.max_freq;
}
PrintKernelWarning("[DX] Emergency boost - CS rate: ");
PrintKernelInt(cs_rate >> FXP_SHIFT);
PrintKernel("\n");
} else if (cs_rate > (8 * FXP_SCALE)) { // Enhanced threshold
target_freq = (target_freq * 1331) >> FXP_SHIFT; // 1.3x boost
consecutive_high_load++;
consecutive_low_load = 0;
controller.emergency_boost_counter = 0;
} else if (cs_rate < (3 * FXP_SCALE) && process_count > 1) { // Higher low threshold
target_freq = (target_freq * 870) >> FXP_SHIFT; // 0.85x gentler reduction
consecutive_low_load++;
consecutive_high_load = 0;
controller.emergency_boost_counter = 0;
} else {
controller.emergency_boost_counter = 0;
}
// Factor 4: Predictive scaling using pattern history
if (controller.history_index > PREDICTION_WINDOW) {
uint32_t predicted_cs = 0;
uint32_t trend_weight = 0;
for (int i = 1; i <= PREDICTION_WINDOW; i++) {
uint32_t idx = (controller.history_index - i) % FREQ_HISTORY_SIZE;
predicted_cs += controller.history[idx].context_switches;
trend_weight += (PREDICTION_WINDOW - i + 1); // Recent samples weighted more
}
predicted_cs = (predicted_cs * trend_weight) /
(PREDICTION_WINDOW * (PREDICTION_WINDOW + 1) / 2);
// Apply prediction if trend suggests increase
if (predicted_cs > cs_delta + (cs_delta / 5)) { // 20% increase predicted
uint16_t prediction_boost = (target_freq * controller.prediction_weight) >> FXP_SHIFT;
target_freq += prediction_boost;
controller.predicted_freq = target_freq;
}
}
// Factor 5: Enhanced adaptive power management
uint32_t load_percentage = (total_queue_depth * 100) / MAX_PROCESSES;
if (consecutive_low_load > 8 && process_count <= 2) {
controller.power_state = 0; // Deep power saving
target_freq = controller.min_freq;
controller.adaptive_mode = 0; // Conservative
} else if (consecutive_high_load > 4 || load_percentage > 50) {
controller.power_state = 2; // Performance mode
target_freq = (target_freq * 1434) >> FXP_SHIFT; // 1.4x turbo
controller.adaptive_mode = 2; // Aggressive
} else if (load_percentage > 75 || controller.emergency_boost_counter > 0) {
controller.power_state = 3; // Maximum performance
target_freq = (target_freq * 1536) >> FXP_SHIFT; // 1.5x max turbo
controller.adaptive_mode = 2;
} else {
controller.power_state = 1; // Balanced
controller.adaptive_mode = 1;
}
// Enhanced learning with adaptive rates
int32_t adaptive_learning = controller.learning_rate;
if (controller.adaptive_mode == 2) {
adaptive_learning = (controller.learning_rate * 3) >> 1; // 1.5x faster
} else if (controller.adaptive_mode == 0) {
adaptive_learning = (controller.learning_rate * 3) >> 2; // 0.75x slower
}
// Apply momentum and learning
int32_t diff = (int32_t)target_freq - (int32_t)controller.current_freq;
int32_t adjustment = (diff * adaptive_learning);
adjustment += (((int64_t)controller.momentum * controller.last_adjustment) >> FXP_SHIFT);
controller.last_adjustment = adjustment;
// Smart frequency application with adaptive bounds
uint16_t new_freq = controller.current_freq + (adjustment >> FXP_SHIFT);
// Dynamic bounds based on power state
uint16_t effective_min = (controller.power_state == 0) ?
controller.min_freq : (controller.min_freq + controller.baseline_freq) / 2;
uint16_t effective_max = (controller.power_state >= 2) ?
controller.max_freq : (controller.max_freq * 4) / 5;
if (new_freq < effective_min) new_freq = effective_min;
if (new_freq > effective_max) new_freq = effective_max;
// Enhanced hysteresis with stability consideration
uint32_t change_threshold = (controller.stability_counter > STABILITY_REQUIREMENT) ?
ENHANCED_HYSTERESIS / 2 : ENHANCED_HYSTERESIS;
if (ABSi(new_freq - controller.current_freq) > change_threshold) {
PitSetFrequency(new_freq);
controller.current_freq = new_freq;
controller.stability_counter = 0;
// Performance feedback scoring
if (cs_rate < (3 * FXP_SCALE)) {
controller.performance_score = MIN(100, controller.performance_score + 1);
} else if (cs_rate > (8 * FXP_SCALE)) {
controller.performance_score = MAX(0, controller.performance_score - 1);
}
} else {
controller.stability_counter++;
}
// Enhanced history recording with more context
uint32_t idx = controller.history_index % FREQ_HISTORY_SIZE;
controller.history[idx] = (FrequencyHistory){
.timestamp = current_time,
.process_count = process_count,
.frequency = controller.current_freq,
.context_switches = cs_delta,
.avg_latency = total_queue_depth | (rt_queue_depth << 8) | (controller.power_state << 16)
};
controller.history_index++;
controller.consecutive_samples++;
// Periodic detailed reporting
if (controller.consecutive_samples % 100 == 0) {
PrintKernel("[DX] Freq: ");
PrintKernelInt(controller.current_freq);
PrintKernel("Hz | Load: ");
PrintKernelInt(load_percentage);
PrintKernel("% | CS: ");
PrintKernelInt(cs_rate >> FXP_SHIFT);
PrintKernel(" | Mode: ");
PrintKernelInt(controller.adaptive_mode);
PrintKernel(" | Score: ");
PrintKernelInt(controller.performance_score);
PrintKernel("\n");
}
last_sample_time = current_time;
last_context_switches = context_switches;
}
// Shorter yield for better responsiveness
for (volatile int i = 0; i < 30000; i++); // Reduced from standard Yield()
}
}
Update the parameters in kernel/process/Process.h
(replace the DynamoX section):
// =============================================================================
// DynamoX Enhanced Parameters (v2.0 - More Responsive & Intelligent)
// =============================================================================
#define FXP_SHIFT 10 // Use 10 bits for the fractional part
#define FXP_SCALE (1 << FXP_SHIFT) // Scaling factor = 1024
#define SAMPLING_INTERVAL 25 // 2x faster sampling (was 50)
#define HZ_PER_PROCESS 80 // More responsive per-process scaling (was 30)
#define QUEUE_PRESSURE_FACTOR 30 // Stronger pressure response (was 20)
#define QUEUE_PRESSURE_THRESHOLD 2 // Earlier pressure detection (was 3)
#define CS_RATE_THRESHOLD_HIGH (8 * FXP_SCALE) // More sensitive high threshold
#define CS_RATE_THRESHOLD_LOW (3 * FXP_SCALE) // Higher low threshold for stability
#define FREQ_BOOST_FACTOR 1331 // Stronger boost: 1.3x (was 1.2x)
#define FREQ_REDUCE_FACTOR 870 // Gentler reduction: 0.85x (was 0.9x)
#define POWER_TURBO_FACTOR 1434 // More aggressive turbo: 1.4x (was 1.3x)
#define HYSTERESIS_THRESHOLD 5 // More responsive changes (was 10)
Key enhancements in this refactor:
- 🚀 2x Faster Response: Sampling every 25 ticks vs 50
- 📈 Higher Performance Range: 200-2000Hz vs 100-1000Hz
- 🧠 Predictive Intelligence: Uses history patterns to anticipate load
- ⚡ Emergency Response: Detects thrashing and immediately turbos
- 🎯 Smart Baselines: 400Hz baseline instead of minimum frequency
- 🔄 Adaptive Learning: Learning rate adjusts based on system state
- 💡 RT Priority Awareness: Real-time processes get frequency priority
- 📊 Performance Feedback: Self-monitors and improves over time
- 🔧 Multi-State Power: 4 power states including emergency mode
- ⚖️ Better Stability: Prevents oscillation while staying responsive
This makes DynamoX significantly more responsive to load changes and much smarter about system behavior prediction. The enhanced version will react faster to load spikes, better handle real-time processes, and provide more stable performance under varying workloads.
Ready for the most important part! What's the next critical component we need to tackle? 🎯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see, also it boost a little to high was it? with 3 process, its 756, which is smooth but is it really needed? but yeah great work, and the thing i was talking about, is none other than, RING 3, the final boss, we need to change a lot of things, like fixing the sched so we can switch and use User Process (add a flag to CreateSecureProcess) and create 2 wrapper, yeah, and make it distinct and stuff, new stack, vmem, and other stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
@assembler-0 You're absolutely right about DynamoX being a bit aggressive! Let me first tune it down and then tackle the Ring 3 implementation - the final boss indeed! 🎯
🏁 Script executed:
#!/bin/bash
# Let's examine the current scheduler, process structures, and memory management for Ring 3 planning
echo "=== Current Process Structure ==="
cat kernel/process/Process.h | grep -A 20 "typedef struct.*Process"
echo -e "\n=== Current Scheduler Implementation ==="
ast-grep --pattern $'void ContextSwitch($_, $_) {
$$$
}'
echo -e "\n=== Current CreateSecureProcess ==="
ast-grep --pattern $'int CreateSecureProcess($$$) {
$$$
}'
echo -e "\n=== Virtual Memory Management ==="
rg "KERNEL_VIRTUAL_BASE|USER.*SPACE" -A 3 -B 3
echo -e "\n=== Current Process Creation and Management ==="
ast-grep --pattern $'Process* CreateProcess($$$) {
$$$
}'
echo -e "\n=== Current Stack Management ==="
rg "stack.*alloc|Stack.*alloc" -A 5 -B 2
Length of output: 3003
🏁 Script executed:
#!/bin/bash
# Let's find the actual process structures and functions
echo "=== Finding Process typedef ==="
rg "typedef.*Process" -A 30
echo -e "\n=== Finding context switch and scheduler ==="
rg "ContextSwitch|context.*switch" -A 10 -B 5
echo -e "\n=== Finding CreateSecureProcess ==="
rg "CreateSecureProcess" -A 15 -B 5
echo -e "\n=== Finding process creation ==="
rg "CreateProcess" -A 15 -B 5
echo -e "\n=== Current Process Management ==="
cat kernel/process/Process.c | head -50
echo -e "\n=== Memory layout and user space definitions ==="
rg "USER.*BASE|USER.*START|USER.*END" -A 2 -B 2
Length of output: 35281
Perfect! Now I have all the pieces. Let me first tune down DynamoX and then implement the complete Ring 3 user mode system.
First, let's fix the DynamoX tuning (you're right, 756Hz for 3 processes is too aggressive):
// In Process.h - Replace the Enhanced DynamoX parameters with more reasonable values:
#define ENHANCED_HZ_PER_PROCESS 50 // Reduced from 80 - more reasonable scaling
#define ENHANCED_QUEUE_PRESSURE 20 // Reduced from 30 - less aggressive
#define HYSTERESIS_THRESHOLD 8 // Increased from 5 - more stable
Now for Ring 3 - The Final Boss! Here's the complete implementation:
1. Enhanced Process Structure (Update Process.h
)
// Add these user space definitions after the existing memory layout
#define USER_SPACE_START 0x0000000000400000ULL // 4MB user space start
#define USER_SPACE_END 0x00007FFFFFFFF000ULL // End before kernel space
#define USER_STACK_START 0x00007FFFFF000000ULL // User stack region
#define USER_STACK_SIZE (2 * 1024 * 1024) // 2MB user stack
#define USER_HEAP_START 0x0000000001000000ULL // 16MB user heap start
#define USER_HEAP_END 0x00007FFF00000000ULL // User heap end
// Ring 3 specific process flags
#define PROC_FLAG_USER_MODE (1U << 4) // Process runs in Ring 3
#define PROC_FLAG_USER_HEAP (1U << 5) // Has user heap allocated
#define PROC_FLAG_USER_STACK (1U << 6) // Has user stack allocated
// Update the Process structure by adding these fields after existing ones:
typedef struct {
uint32_t pid;
ProcessState state;
void* stack; // Kernel stack
void* user_stack; // User mode stack
void* user_heap_base; // User heap base address
size_t user_heap_size; // Current user heap size
uint64_t user_cr3; // User page directory (if using separate address space)
uint8_t priority;
uint8_t base_priority;
uint8_t is_user_mode; // Legacy field - now use flags
uint8_t privilege_level;
uint32_t cpu_burst_history[CPU_BURST_HISTORY];
uint32_t io_operations;
uint32_t preemption_count;
uint64_t cpu_time_accumulated;
uint64_t last_scheduled_tick;
uint64_t wait_time;
TerminationReason term_reason;
uint32_t exit_code;
uint64_t termination_time;
uint32_t parent_pid;
SecurityToken token;
MessageQueue ipc_queue;
ProcessContext context;
ProcessContext user_context; // Separate user mode context
SchedulerNode* scheduler_node;
uint64_t creation_time;
} Process;
// Add Ring 3 function declarations
uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege, bool user_mode);
uint32_t CreateUserProcess(void (*entry_point)(void));
void JumpToUserMode(uint32_t pid);
void* AllocateUserStack(Process* proc);
void* AllocateUserHeap(Process* proc, size_t size);
void FreeUserSpace(Process* proc);
bool IsUserModeProcess(Process* proc);
void SetupUserModeContext(Process* proc, void (*entry_point)(void));
2. Enhanced Process Creation (Process.c
)
// Update CreateSecureProcess to support user mode flag
uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege, bool user_mode) {
irq_flags_t flags = SpinLockIrqSave(&scheduler_lock);
if (UNLIKELY(!entry_point)) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: NULL entry point");
}
Process* creator = GetCurrentProcess();
// Enhanced security validation
if (UNLIKELY(!ValidateToken(&creator->token, creator->pid))) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
SecurityViolationHandler(creator->pid, "Corrupt token during process creation");
return 0;
}
// Ring 3 privilege validation
if (user_mode && privilege == PROC_PRIV_SYSTEM) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
PrintKernelError("[SECURITY] Cannot create user mode system process\n");
return 0;
}
// Privilege escalation check
if (privilege == PROC_PRIV_SYSTEM && !user_mode) {
if (UNLIKELY(creator->pid != 0 && creator->privilege_level != PROC_PRIV_SYSTEM)) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
SecurityViolationHandler(creator->pid, "Privilege escalation attempt");
return 0;
}
}
if (UNLIKELY(process_count >= MAX_PROCESSES)) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: Too many processes");
}
// Fast slot allocation
int slot = FindFreeSlotFast();
if (UNLIKELY(slot == -1)) {
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: No free process slots");
}
uint32_t new_pid = 0;
SpinLock(&pid_lock);
for (int i = 1; i < MAX_PROCESSES; i++) {
int idx = i / 64;
int bit = i % 64;
if (!(pid_bitmap[idx] & (1ULL << bit))) {
pid_bitmap[idx] |= (1ULL << bit);
new_pid = i;
break;
}
}
SpinUnlock(&pid_lock);
if (new_pid == 0) {
FreeSlotFast(slot);
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: PID exhaustion");
}
// Clear slot securely
FastMemset(&processes[slot], 0, sizeof(Process));
// Allocate kernel stack (always needed)
void* stack = VMemAllocWithGuards(STACK_SIZE);
if (UNLIKELY(!stack)) {
FreeSlotFast(slot);
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: Failed to allocate kernel stack");
}
// Initialize basic process data
processes[slot].pid = new_pid;
processes[slot].state = PROC_READY;
processes[slot].stack = stack;
processes[slot].privilege_level = privilege;
processes[slot].priority = (privilege == PROC_PRIV_SYSTEM) ? 0 : RT_PRIORITY_THRESHOLD;
processes[slot].base_priority = processes[slot].priority;
processes[slot].is_user_mode = user_mode;
processes[slot].scheduler_node = NULL;
processes[slot].creation_time = GetSystemTicks();
processes[slot].last_scheduled_tick = GetSystemTicks();
processes[slot].parent_pid = creator->pid;
// Initialize user mode specific fields
processes[slot].user_stack = NULL;
processes[slot].user_heap_base = NULL;
processes[slot].user_heap_size = 0;
processes[slot].user_cr3 = 0;
// Set user mode flags
if (user_mode) {
processes[slot].token.flags |= PROC_FLAG_USER_MODE;
// Allocate user space
if (!AllocateUserStack(&processes[slot])) {
FreeUserSpace(&processes[slot]);
VMemFree(stack);
FreeSlotFast(slot);
SpinUnlockIrqRestore(&scheduler_lock, flags);
PANIC("CreateSecureProcess: Failed to allocate user stack");
}
// Setup user mode execution context
SetupUserModeContext(&processes[slot], entry_point);
PrintKernelSuccess("[RING3] User process created - PID: ");
PrintKernelInt(new_pid);
PrintKernel(", User Stack: 0x");
PrintKernelHex((uint64_t)processes[slot].user_stack);
PrintKernel("\n");
} else {
// Setup kernel mode execution context (existing logic)
uint64_t* rsp = (uint64_t*)((uint8_t*)stack + STACK_SIZE);
rsp--; *rsp = (uint64_t)entry_point; // RIP
rsp--; *rsp = 0x08; // CS (kernel code segment)
rsp--; *rsp = 0x202; // RFLAGS (IF=1)
rsp--; *rsp = (uint64_t)rsp + 32; // RSP
rsp--; *rsp = 0x10; // SS (kernel data segment)
processes[slot].context.rsp = (uint64_t)rsp;
}
// Security token setup
processes[slot].token.magic = SECURITY_MAGIC;
processes[slot].token.salt = SECURITY_SALT ^ new_pid;
processes[slot].token.timestamp = GetSystemTicks();
processes[slot].token.checksum = CalculateSecureChecksum(&processes[slot].token, new_pid);
// Add to scheduler and bitmaps
active_process_bitmap |= (1ULL << slot);
ready_process_bitmap |= (1ULL << slot);
process_count++;
AddToScheduler(slot);
SpinUnlockIrqRestore(&scheduler_lock, flags);
return new_pid;
}
// Wrapper functions for user mode process creation
uint32_t CreateUserProcess(void (*entry_point)(void)) {
return CreateSecureProcess(entry_point, PROC_PRIV_USER, true);
}
uint32_t CreateProcess(void (*entry_point)(void)) {
return CreateSecureProcess(entry_point, PROC_PRIV_USER, false); // Keep backward compatibility
}
// User space memory management
void* AllocateUserStack(Process* proc) {
if (!proc || !(proc->token.flags & PROC_FLAG_USER_MODE)) {
return NULL;
}
// Allocate user stack in user address space
void* user_stack = VMemAllocAt((void*)USER_STACK_START, USER_STACK_SIZE);
if (!user_stack) {
PrintKernelError("[RING3] Failed to allocate user stack\n");
return NULL;
}
proc->user_stack = user_stack;
proc->token.flags |= PROC_FLAG_USER_STACK;
return user_stack;
}
void* AllocateUserHeap(Process* proc, size_t size) {
if (!proc || !(proc->token.flags & PROC_FLAG_USER_MODE)) {
return NULL;
}
if (!proc->user_heap_base) {
// First heap allocation
proc->user_heap_base = VMemAllocAt((void*)USER_HEAP_START, size);
if (!proc->user_heap_base) {
return NULL;
}
proc->user_heap_size = size;
proc->token.flags |= PROC_FLAG_USER_HEAP;
return proc->user_heap_base;
} else {
// Expand existing heap
size_t new_size = proc->user_heap_size + size;
if ((uint64_t)proc->user_heap_base + new_size >= USER_HEAP_END) {
return NULL; // Heap would exceed user space
}
// Try to extend the heap
void* extension = VMemAlloc(size);
if (extension) {
proc->user_heap_size = new_size;
}
return extension;
}
}
void SetupUserModeContext(Process* proc, void (*entry_point)(void)) {
if (!proc || !proc->user_stack) {
return;
}
// Setup user mode context for Ring 3 execution
uint64_t user_stack_top = (uint64_t)proc->user_stack + USER_STACK_SIZE;
// User mode segments (Ring 3)
uint16_t user_cs = 0x18 | 0x03; // User code segment with RPL=3
uint16_t user_ss = 0x20 | 0x03; // User data segment with RPL=3
// Setup kernel stack for iretq to user mode
uint64_t* kernel_rsp = (uint64_t*)((uint8_t*)proc->stack + STACK_SIZE);
// Push user mode iretq frame onto kernel stack
kernel_rsp--; *kernel_rsp = user_ss; // SS
kernel_rsp--; *kernel_rsp = user_stack_top - 8; // RSP
kernel_rsp--; *kernel_rsp = 0x202; // RFLAGS (IF=1)
kernel_rsp--; *kernel_rsp = user_cs; // CS
kernel_rsp--; *kernel_rsp = (uint64_t)entry_point; // RIP
// Set kernel stack pointer
proc->context.rsp = (uint64_t)kernel_rsp;
// Initialize user context (for syscall returns)
proc->user_context.rip = (uint64_t)entry_point;
proc->user_context.rsp = user_stack_top - 8;
proc->user_context.cs = user_cs;
proc->user_context.ss = user_ss;
proc->user_context.rflags = 0x202;
PrintKernelSuccess("[RING3] Context setup complete - Entry: 0x");
PrintKernelHex((uint64_t)entry_point);
PrintKernel(", User Stack: 0x");
PrintKernelHex(user_stack_top);
PrintKernel("\n");
}
void FreeUserSpace(Process* proc) {
if (!proc) return;
if (proc->user_stack && (proc->token.flags & PROC_FLAG_USER_STACK)) {
VMemFree(proc->user_stack);
proc->user_stack = NULL;
proc->token.flags &= ~PROC_FLAG_USER_STACK;
}
if (proc->user_heap_base && (proc->token.flags & PROC_FLAG_USER_HEAP)) {
VMemFree(proc->user_heap_base);
proc->user_heap_base = NULL;
proc->user_heap_size = 0;
proc->token.flags &= ~PROC_FLAG_USER_HEAP;
}
proc->token.flags &= ~PROC_FLAG_USER_MODE;
}
bool IsUserModeProcess(Process* proc) {
return proc && (proc->token.flags & PROC_FLAG_USER_MODE);
}
// Ring 3 transition function
void JumpToUserMode(uint32_t pid) {
Process* proc = GetProcessByPid(pid);
if (!proc || !IsUserModeProcess(proc)) {
PrintKernelError("[RING3] Invalid user mode process\n");
return;
}
// Enable user mode access
__asm__ volatile(
"mov %0, %%rsp\n\t" // Set kernel stack
"sti\n\t" // Enable interrupts
"iretq" // Jump to Ring 3
:
: "r"(proc->context.rsp)
: "memory"
);
}
3. Enhanced Scheduler for Ring 3 Context Switching
// Update FastSchedule to handle Ring 3 context switches
void FastSchedule(struct Registers* regs) {
uint64_t schedule_start = MLFQscheduler.tick_counter;
irq_flags_t flags = SpinLockIrqSave(&scheduler_lock);
MLFQscheduler.tick_counter++;
scheduler_calls++;
int old_slot = current_process;
Process* old_proc = (old_slot < MAX_PROCESSES) ? &processes[old_slot] : NULL;
// Handle Ring 3 context save
if (old_proc && IsUserModeProcess(old_proc) && old_proc->state == PROC_RUNNING) {
// Save user mode context for syscall/interrupt return
old_proc->user_context = *regs;
PrintKernelDebug("[RING3] Saved user context for PID ");
PrintKernelInt(old_proc->pid);
PrintKernel(" - RIP: 0x");
PrintKernelHex(regs->rip);
PrintKernel("\n");
}
// Save current process context (existing logic)
if (old_proc && old_proc->state == PROC_RUNNING) {
FastMemcpy(&old_proc->context, regs, sizeof(struct Registers));
}
// Find next process (existing scheduler logic)
int new_slot = SelectNextProcess();
if (new_slot != -1 && new_slot != old_slot) {
Process* new_proc = &processes[new_slot];
// Handle Ring 3 context restore
if (IsUserModeProcess(new_proc)) {
// For user mode processes, we need to set up for return to user space
if (new_proc->user_context.rip != 0) {
// Restore user context
*regs = new_proc->user_context;
PrintKernelDebug("[RING3] Restored user context for PID ");
PrintKernelInt(new_proc->pid);
PrintKernel(" - RIP: 0x");
PrintKernelHex(regs->rip);
PrintKernel("\n");
} else {
// First time scheduling - use kernel context to iretq to user mode
FastMemcpy(regs, &new_proc->context, sizeof(struct Registers));
}
} else {
// Kernel mode process - normal context switch
FastMemcpy(regs, &new_proc->context, sizeof(struct Registers));
}
// Update process states
if (old_proc && old_proc->state == PROC_RUNNING) {
old_proc->state = PROC_READY;
ready_process_bitmap |= (1ULL << old_slot);
}
new_proc->state = PROC_RUNNING;
ready_process_bitmap &= ~(1ULL << new_slot);
current_process = new_slot;
// Reset quantum
uint32_t base_quantum = MLFQ_BASE_QUANTUM << new_proc->priority;
MLFQscheduler.quantum_remaining = base_quantum;
new_proc->last_scheduled_tick = MLFQscheduler.tick_counter;
AtomicInc(&context_switches);
// Update context switch overhead measurement
uint32_t overhead = MLFQscheduler.tick_counter - schedule_start;
MLFQscheduler.context_switch_overhead = (MLFQscheduler.context_switch_overhead * 7 + overhead) / 8;
}
SpinUnlockIrqRestore(&scheduler_lock, flags);
}
4. System Call Interface Updates (Update Syscall.c
)
// Add Ring 3 syscall handling
static int64_t HandleRing3Syscall(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, Registers* regs) {
Process* current = GetCurrentProcess();
if (!current || !IsUserModeProcess(current)) {
return -1; // Only user mode processes can make syscalls
}
// Validate user space pointers
switch (syscall_num) {
case SYS_WRITE:
if (!is_user_address((void*)arg2, arg3)) {
PrintKernelError("[RING3] Invalid user buffer in write syscall\n");
return -1;
}
break;
case SYS_FREAD:
if (!is_user_address((void*)arg1, FastStrlen((char*)arg1)) ||
!is_user_address((void*)arg2, arg3)) {
PrintKernelError("[RING3] Invalid user pointers in fread syscall\n");
return -1;
}
break;
}
// Execute syscall with existing logic
return HandleKernelSyscall(syscall_num, arg1, arg2, arg3);
}
// Update main Syscall function
int64_t Syscall(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, Registers* regs) {
Process* current = GetCurrentProcess();
if (IsUserModeProcess(current)) {
return HandleRing3Syscall(syscall_num, arg1, arg2, arg3, regs);
} else {
return HandleKernelSyscall(syscall_num, arg1, arg2, arg3);
}
}
5. Test User Mode Process
// Add to Shell.c for testing Ring 3
void TestUserProcess(void) {
PrintKernel("Hello from Ring 3! This is a user mode process.\n");
// Test syscall
char* message = "Writing from Ring 3 user process\n";
asm volatile(
"mov $1, %%rax\n\t" // SYS_WRITE
"mov $1, %%rdi\n\t" // stdout
"mov %0, %%rsi\n\t" // message
"mov %1, %%rdx\n\t" // length
"syscall"
:
: "r"(message), "r"(FastStrlen(message))
: "rax", "rdi", "rsi", "rdx"
);
while (1) {
for (volatile int i = 0; i < 1000000; i++);
PrintKernel("[USER] Still alive in Ring 3!\n");
}
}
// Add to shell commands
} else if (FastStrCmp(cmd_name, "ring3") == 0) {
PrintKernel("Creating Ring 3 user process...\n");
uint32_t pid = CreateUserProcess(TestUserProcess);
if (pid > 0) {
PrintKernelSuccess("Ring 3 process created with PID: ");
PrintKernelInt(pid);
PrintKernel("\n");
} else {
PrintKernelError("Failed to create Ring 3 process\n");
}
This complete Ring 3 implementation provides:
- 🔐 Process Isolation: Separate user/kernel address spaces
- 🚀 Context Switching: Full Ring 3 ↔ Ring 0 transitions
- 🛡️ Memory Protection: User space validation and guards
- 📞 System Calls: Secure Ring 3 → Ring 0 interface
- 🎯 Scheduler Integration: Enhanced scheduler handles user processes
- ⚡ Performance: Optimized context switching with separate stacks
- 🧪 Testing: Complete test framework with shell command
The implementation maintains full backward compatibility while adding comprehensive Ring 3 support. Ready to deploy the final boss! 🎯
✏️ Learnings added
Learnt from: assembler-0
PR: assembler-0/VoidFrame#75
File: drivers/RTC/Rtc.c:76-84
Timestamp: 2025-08-12T10:10:28.009Z
Learning: DynamoX frequency controller was boosting too aggressively at 80Hz per process, causing 756Hz for just 3 processes. More reasonable scaling should be around 50Hz per process for better balance between responsiveness and resource usage.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, that should work, also i think theres a bit confusion here, the VMemAllocAt doesnt exist,can you check and try again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
@assembler-0 You're absolutely right! Let me check the actual virtual memory management functions available and fix the Ring 3 implementation.
🏁 Script executed:
#!/bin/bash
# Find actual virtual memory allocation functions
echo "=== Virtual Memory Management Functions ==="
rg "VMemAlloc|VMem.*alloc|vmem.*alloc" -A 5 -B 2
echo -e "\n=== Memory allocation function definitions ==="
ast-grep --pattern $'$_* VMemAlloc$$$($$$) {
$$$
}'
echo -e "\n=== All memory-related function declarations ==="
rg ".*Alloc.*\(" -A 2 -B 1 | head -30
echo -e "\n=== Virtual memory header files ==="
fd -t f -e h | xargs rg -l "VMemAlloc|VMem" | head -5
echo -e "\n=== Check VMem.h contents ==="
cat kernel/memory/VMem.h 2>/dev/null || echo "VMem.h not found"
echo -e "\n=== Check for page allocation functions ==="
rg "AllocPage|alloc.*page|Page.*alloc" -A 3 -B 1
Length of output: 16207
Perfect! Now I can see the actual memory management functions. You're absolutely right - there's no VMemAllocAt
. Let me fix the Ring 3 implementation to use the correct memory allocation approach:
Here's the corrected Ring 3 user space allocation functions:
// User space memory management - CORRECTED VERSION
void* AllocateUserStack(Process* proc) {
if (!proc || !(proc->token.flags & PROC_FLAG_USER_MODE)) {
return NULL;
}
// Allocate physical pages for user stack
uint32_t stack_pages = USER_STACK_SIZE / PAGE_SIZE;
void** phys_pages = KernelMemoryAlloc(stack_pages * sizeof(void*));
if (!phys_pages) {
PrintKernelError("[RING3] Failed to allocate physical page array\n");
return NULL;
}
// Allocate physical pages
for (uint32_t i = 0; i < stack_pages; i++) {
phys_pages[i] = AllocPage();
if (!phys_pages[i]) {
PrintKernelError("[RING3] Failed to allocate physical page for user stack\n");
// Free already allocated pages
for (uint32_t j = 0; j < i; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
// Map user stack virtual addresses to physical pages
uint64_t user_stack_vaddr = USER_STACK_START;
uint64_t flags = PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for (uint32_t i = 0; i < stack_pages; i++) {
uint64_t vaddr = user_stack_vaddr + (i * PAGE_SIZE);
uint64_t paddr = (uint64_t)phys_pages[i];
int result = VMemMap(vaddr, paddr, flags);
if (result != 0) {
PrintKernelError("[RING3] Failed to map user stack page\n");
// Unmap already mapped pages and free physical pages
for (uint32_t j = 0; j < i; j++) {
VMemUnmap(user_stack_vaddr + (j * PAGE_SIZE), PAGE_SIZE);
}
for (uint32_t j = 0; j < stack_pages; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
KernelMemoryFree(phys_pages); // Free the page array, we no longer need it
proc->user_stack = (void*)user_stack_vaddr;
proc->token.flags |= PROC_FLAG_USER_STACK;
PrintKernelSuccess("[RING3] User stack allocated: 0x");
PrintKernelHex(user_stack_vaddr);
PrintKernel(" - 0x");
PrintKernelHex(user_stack_vaddr + USER_STACK_SIZE);
PrintKernel("\n");
return (void*)user_stack_vaddr;
}
void* AllocateUserHeap(Process* proc, size_t size) {
if (!proc || !(proc->token.flags & PROC_FLAG_USER_MODE)) {
return NULL;
}
// Align size to page boundary
size = PAGE_ALIGN_UP(size);
uint32_t pages_needed = size / PAGE_SIZE;
if (!proc->user_heap_base) {
// First heap allocation - allocate at USER_HEAP_START
void** phys_pages = KernelMemoryAlloc(pages_needed * sizeof(void*));
if (!phys_pages) {
return NULL;
}
// Allocate physical pages
for (uint32_t i = 0; i < pages_needed; i++) {
phys_pages[i] = AllocPage();
if (!phys_pages[i]) {
// Free already allocated pages
for (uint32_t j = 0; j < i; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
// Map user heap virtual addresses
uint64_t user_heap_vaddr = USER_HEAP_START;
uint64_t flags = PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for (uint32_t i = 0; i < pages_needed; i++) {
uint64_t vaddr = user_heap_vaddr + (i * PAGE_SIZE);
uint64_t paddr = (uint64_t)phys_pages[i];
int result = VMemMap(vaddr, paddr, flags);
if (result != 0) {
// Cleanup on failure
for (uint32_t j = 0; j < i; j++) {
VMemUnmap(user_heap_vaddr + (j * PAGE_SIZE), PAGE_SIZE);
}
for (uint32_t j = 0; j < pages_needed; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
KernelMemoryFree(phys_pages);
proc->user_heap_base = (void*)user_heap_vaddr;
proc->user_heap_size = size;
proc->token.flags |= PROC_FLAG_USER_HEAP;
PrintKernelSuccess("[RING3] User heap allocated: 0x");
PrintKernelHex(user_heap_vaddr);
PrintKernel(" (");
PrintKernelInt(pages_needed);
PrintKernel(" pages)\n");
return (void*)user_heap_vaddr;
} else {
// Expand existing heap
uint64_t current_end = (uint64_t)proc->user_heap_base + proc->user_heap_size;
// Check if expansion would exceed user space
if (current_end + size >= USER_HEAP_END) {
PrintKernelError("[RING3] Heap expansion would exceed user space\n");
return NULL;
}
// Allocate physical pages for expansion
void** phys_pages = KernelMemoryAlloc(pages_needed * sizeof(void*));
if (!phys_pages) {
return NULL;
}
for (uint32_t i = 0; i < pages_needed; i++) {
phys_pages[i] = AllocPage();
if (!phys_pages[i]) {
for (uint32_t j = 0; j < i; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
// Map the expansion
uint64_t flags = PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for (uint32_t i = 0; i < pages_needed; i++) {
uint64_t vaddr = current_end + (i * PAGE_SIZE);
uint64_t paddr = (uint64_t)phys_pages[i];
int result = VMemMap(vaddr, paddr, flags);
if (result != 0) {
// Cleanup expansion on failure
for (uint32_t j = 0; j < i; j++) {
VMemUnmap(current_end + (j * PAGE_SIZE), PAGE_SIZE);
}
for (uint32_t j = 0; j < pages_needed; j++) {
FreePage(phys_pages[j]);
}
KernelMemoryFree(phys_pages);
return NULL;
}
}
KernelMemoryFree(phys_pages);
proc->user_heap_size += size;
PrintKernelSuccess("[RING3] Heap expanded by ");
PrintKernelInt(pages_needed);
PrintKernel(" pages\n");
return (void*)current_end;
}
}
void FreeUserSpace(Process* proc) {
if (!proc) return;
// Free user stack
if (proc->user_stack && (proc->token.flags & PROC_FLAG_USER_STACK)) {
uint32_t stack_pages = USER_STACK_SIZE / PAGE_SIZE;
uint64_t stack_vaddr = (uint64_t)proc->user_stack;
// Unmap and free each page
for (uint32_t i = 0; i < stack_pages; i++) {
uint64_t vaddr = stack_vaddr + (i * PAGE_SIZE);
uint64_t paddr = VMemGetPhysAddr(vaddr);
if (paddr) {
VMemUnmap(vaddr, PAGE_SIZE);
FreePage((void*)paddr);
}
}
proc->user_stack = NULL;
proc->token.flags &= ~PROC_FLAG_USER_STACK;
PrintKernelSuccess("[RING3] User stack freed\n");
}
// Free user heap
if (proc->user_heap_base && (proc->token.flags & PROC_FLAG_USER_HEAP)) {
uint32_t heap_pages = proc->user_heap_size / PAGE_SIZE;
uint64_t heap_vaddr = (uint64_t)proc->user_heap_base;
// Unmap and free each page
for (uint32_t i = 0; i < heap_pages; i++) {
uint64_t vaddr = heap_vaddr + (i * PAGE_SIZE);
uint64_t paddr = VMemGetPhysAddr(vaddr);
if (paddr) {
VMemUnmap(vaddr, PAGE_SIZE);
FreePage((void*)paddr);
}
}
proc->user_heap_base = NULL;
proc->user_heap_size = 0;
proc->token.flags &= ~PROC_FLAG_USER_HEAP;
PrintKernelSuccess("[RING3] User heap freed\n");
}
proc->token.flags &= ~PROC_FLAG_USER_MODE;
}
// Enhanced user mode transition with proper address validation
void JumpToUserMode(uint32_t pid) {
Process* proc = GetProcessByPid(pid);
if (!proc || !IsUserModeProcess(proc)) {
PrintKernelError("[RING3] Invalid user mode process for PID ");
PrintKernelInt(pid);
PrintKernel("\n");
return;
}
// Validate user space is properly mapped
if (!proc->user_stack) {
PrintKernelError("[RING3] User stack not allocated for PID ");
PrintKernelInt(pid);
PrintKernel("\n");
return;
}
// Validate the user stack is mapped
uint64_t stack_paddr = VMemGetPhysAddr((uint64_t)proc->user_stack);
if (!stack_paddr) {
PrintKernelError("[RING3] User stack not mapped for PID ");
PrintKernelInt(pid);
PrintKernel("\n");
return;
}
PrintKernelSuccess("[RING3] Jumping to Ring 3 for PID ");
PrintKernelInt(pid);
PrintKernel(" - Stack: 0x");
PrintKernelHex((uint64_t)proc->user_stack);
PrintKernel("\n");
// Switch to user process context and jump to Ring 3
current_process = GetProcessSlotByPid(pid);
// Set up for Ring 3 transition via scheduler
proc->state = PROC_RUNNING;
// Enable user mode access in CR4 if needed
__asm__ volatile(
"mov %0, %%rsp\n\t" // Set kernel stack for iretq
"sti\n\t" // Enable interrupts
"iretq" // Jump to Ring 3 via pre-setup context
:
: "r"(proc->context.rsp)
: "memory"
);
}
Also add these helper functions:
// Helper to check if address is in user space range
bool IsUserSpaceAddress(uint64_t addr) {
return (addr >= USER_SPACE_START && addr < USER_SPACE_END);
}
// Enhanced user mode process validation
bool IsUserModeProcess(Process* proc) {
return proc && (proc->token.flags & PROC_FLAG_USER_MODE) &&
proc->user_stack != NULL;
}
// Get process slot by PID helper
int GetProcessSlotByPid(uint32_t pid) {
for (int i = 0; i < MAX_PROCESSES; i++) {
if (processes[i].pid == pid && processes[i].state != PROC_FREE) {
return i;
}
}
return -1;
}
Key corrections made:
- 🔧 Proper Memory Mapping: Uses
VMemMap()
to map specific user virtual addresses to allocated physical pages - 📦 Physical Page Allocation: Uses
AllocPage()
to get physical pages for user space - 🎯 Correct User Flags: Sets
PAGE_USER | PAGE_WRITABLE
flags for proper Ring 3 access - 🧹 Proper Cleanup: Unmaps virtual addresses and frees physical pages on failure/termination
- ✅ Address Validation: Checks that user stack is properly mapped before Ring 3 transition
- 🔍 Memory Layout Compliance: Uses the defined USER_SPACE_START, USER_STACK_START, USER_HEAP_START constants
This corrected version uses the actual VMem API available in your codebase and should work properly with the Ring 3 implementation! The user space memory is now correctly allocated using physical pages mapped to specific user virtual addresses. 🎯
🧠 Learnings used
Learnt from: assembler-0
PR: assembler-0/VoidFrame#75
File: drivers/RTC/Rtc.c:76-84
Timestamp: 2025-08-12T10:10:28.009Z
Learning: DynamoX frequency controller was boosting too aggressively at 80Hz per process, causing 756Hz for just 3 processes. More reasonable scaling should be around 50Hz per process for better balance between responsiveness and resource usage.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores