Skip to content

Commit 0dc5d0b

Browse files
committed
Fixed GPF error due to Heap Fragmentation and an Out-Of-Memory
1 parent b16fe50 commit 0dc5d0b

7 files changed

Lines changed: 114 additions & 92 deletions

File tree

nyx-kernel/src/gui.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use noto_sans_mono_bitmap::{get_raster, FontWeight, RasterHeight};
33
use alloc::vec::Vec;
44
use alloc::vec;
55

6-
// Store Physical Address of Framebuffer here (for Syscalls)
76
pub static mut SCREEN_PAINTER: Option<VgaPainter<'static>> = None;
87
pub static mut BACK_BUFFER: Option<BackBuffer> = None;
98
pub static mut FRAMEBUFFER_PHYS_ADDR: u64 = 0;
@@ -33,19 +32,15 @@ impl Color {
3332
pub fn new(r: u8, g: u8, b: u8) -> Self { Self { r, g, b } }
3433
}
3534

36-
// --- TURBO COPY: Optimized 64-bit Memory Copy ---
37-
// Uses u64 writes to move 8 bytes at a time, significantly faster than byte-by-byte.
3835
pub unsafe fn turbo_copy(dest: *mut u8, src: *const u8, count: usize) {
3936
let mut i = 0;
4037

41-
// Bulk Copy (u64)
4238
while i + 8 <= count {
4339
let val = *(src.add(i) as *const u64);
4440
*(dest.add(i) as *mut u64) = val;
4541
i += 8;
4642
}
4743

48-
// Trailing Bytes
4944
while i < count {
5045
*dest.add(i) = *src.add(i);
5146
i += 1;
@@ -61,7 +56,6 @@ pub trait Painter {
6156
fn height(&self) -> usize;
6257
}
6358

64-
// --- HARDWARE PAINTER (Direct VRAM Access) ---
6559
pub struct VgaPainter<'a> {
6660
pub buffer: &'a mut [u8],
6761
pub info: FrameBufferInfo,
@@ -86,7 +80,8 @@ impl<'a> Painter for VgaPainter<'a> {
8680
if byte_offset >= self.buffer.len() { break; }
8781

8882
for x in 0..rect.w {
89-
if rect.x + x >= self.info.width { break; }
83+
// FIX: Use saturating_add to prevent boundary check bypass on underflow
84+
if rect.x.saturating_add(x) >= self.info.width { break; }
9085
let idx = byte_offset + (x * bpp);
9186

9287
if idx + 2 < self.buffer.len() {
@@ -149,23 +144,20 @@ impl<'a> Painter for VgaPainter<'a> {
149144
}
150145
}
151146

152-
// --- SOFTWARE BACKBUFFER (Double Buffering) ---
153147
pub struct BackBuffer {
154148
pub buffer: Vec<u8>,
155149
pub info: FrameBufferInfo,
156150
}
157151

158152
impl BackBuffer {
159153
pub fn new(info: FrameBufferInfo) -> Self {
160-
// IMPORTANT: We use stride here to match hardware layout exactly
161154
let size = info.stride * info.height * info.bytes_per_pixel;
162155
Self {
163156
buffer: vec![0; size],
164157
info,
165158
}
166159
}
167160

168-
// Flips the backbuffer to the screen
169161
pub fn present(&self, screen: &mut VgaPainter) {
170162
let len = self.buffer.len().min(screen.buffer.len());
171163
unsafe {
@@ -202,7 +194,6 @@ impl Painter for BackBuffer {
202194

203195
fn clear(&mut self, color: Color) {
204196
if color == Color::BLACK {
205-
// Turbo Clear (memset 0)
206197
self.buffer.fill(0);
207198
return;
208199
}
@@ -219,7 +210,8 @@ impl Painter for BackBuffer {
219210
let mut idx = offset * bpp;
220211

221212
for x in 0..rect.w {
222-
if rect.x + x >= self.width() { break; }
213+
// FIX: Use saturating_add to prevent boundary check bypass on underflow
214+
if rect.x.saturating_add(x) >= self.width() { break; }
223215
self.put_pixel(idx, color);
224216
idx += bpp;
225217
}

nyx-kernel/src/nyx-user.bin

4.51 KB
Binary file not shown.

nyx-kernel/src/window.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use lazy_static::lazy_static;
55
use crate::gui::{Painter, Rect, Color, turbo_copy};
66
use crate::mouse::MouseState;
77
use core::fmt::Write;
8-
use bootloader_api::info::PixelFormat; // Required for the green-shift fix
8+
use bootloader_api::info::PixelFormat;
99

1010
lazy_static! {
1111
pub static ref WINDOW_MANAGER: Mutex<WindowManager> = Mutex::new(WindowManager::new());
@@ -71,7 +71,8 @@ impl Window {
7171
painter.draw_rect(Rect::new(self.x + 6, self.y + 6, self.w, self.h), Color::new(5, 5, 5));
7272

7373
let border_color = if is_active { Color::new(200, 200, 200) } else { Color::new(60, 60, 60) };
74-
painter.draw_rect(Rect::new(self.x - 2, self.y - 2, self.w + 4, self.h + 4), border_color);
74+
// FIX: Use saturating_sub to prevent GPF when dragging past the left/top edges
75+
painter.draw_rect(Rect::new(self.x.saturating_sub(2), self.y.saturating_sub(2), self.w + 4, self.h + 4), border_color);
7576
painter.draw_rect(Rect::new(self.x, self.y, self.w, self.h), self.content_color);
7677

7778
let header_color = if is_active {
@@ -142,7 +143,6 @@ impl WindowManager {
142143
}
143144
}
144145

145-
// --- THIS IS THE MISSING METHOD CAUSING YOUR ERROR ---
146146
pub fn console_print(&mut self, c: char) {
147147
for win in self.windows.iter_mut().rev() {
148148
if win.window_type == WindowType::DebugLog {
@@ -157,9 +157,7 @@ impl WindowManager {
157157
self.prev_left = mouse.left_click; self.prev_right = mouse.right_click;
158158
}
159159

160-
// Handles both Stride AND Pixel Format (3 vs 4 bytes)
161160
pub fn draw(&self, painter: &mut crate::gui::BackBuffer) {
162-
// Only draw desktop if buffer is ready
163161
if self.desktop_buffer.len() == self.screen_width * self.screen_height {
164162
let stride = painter.info.stride;
165163
let width = self.screen_width;
@@ -169,25 +167,20 @@ impl WindowManager {
169167

170168
match bpp {
171169
4 => {
172-
// Optimized path for 32-bit (4 byte) color
173170
for y in 0..height {
174171
let src_idx = y * width;
175172
let dest_offset = (y * stride) * 4;
176173

177-
// Bounds check
178174
if src_idx < self.desktop_buffer.len() && dest_offset < painter.buffer.len() {
179175
unsafe {
180176
let src_ptr = self.desktop_buffer.as_ptr().add(src_idx) as *const u8;
181177
let dest_ptr = painter.buffer.as_mut_ptr().add(dest_offset);
182-
// We copy exactly 'width' pixels
183178
turbo_copy(dest_ptr, src_ptr, width * 4);
184179
}
185180
}
186181
}
187182
},
188183
3 => {
189-
// Slow path for 24-bit (3 byte) color
190-
// We must manually convert u32 (0xRRGGBB) -> 3 bytes
191184
for y in 0..height {
192185
let src_start = y * width;
193186
let dest_start = (y * stride) * 3;
@@ -197,7 +190,6 @@ impl WindowManager {
197190
let dest_idx = dest_start + (x * 3);
198191

199192
if dest_idx + 2 < painter.buffer.len() {
200-
// Extract RGB
201193
let r = ((color >> 16) & 0xFF) as u8;
202194
let g = ((color >> 8) & 0xFF) as u8;
203195
let b = (color & 0xFF) as u8;
@@ -218,13 +210,12 @@ impl WindowManager {
218210
}
219211
}
220212
},
221-
_ => {} // Not supported
213+
_ => {}
222214
}
223215
} else {
224216
painter.clear(Color::new(0, 0, 30));
225217
}
226218

227-
// Draw Kernel Windows
228219
for (i, w) in self.windows.iter().enumerate() {
229220
w.draw(painter, i == self.windows.len()-1);
230221
}

nyx-user/src/apps/monitor.rs

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
1-
use alloc::format;
21
use crate::gfx::draw;
3-
use crate::syscalls::{sys_get_system_info, SystemInfo, TaskInfo};
2+
use crate::syscalls::{sys_get_system_info, SystemInfo};
3+
use core::fmt::Write;
4+
5+
// --- A lightweight, heap-free string buffer ---
6+
struct StackString<const N: usize> {
7+
buf: [u8; N],
8+
len: usize,
9+
}
10+
11+
impl<const N: usize> StackString<N> {
12+
fn new() -> Self { Self { buf: [0; N], len: 0 } }
13+
fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.len]).unwrap_or("") }
14+
}
15+
16+
impl<const N: usize> core::fmt::Write for StackString<N> {
17+
fn write_str(&mut self, s: &str) -> core::fmt::Result {
18+
for b in s.bytes() {
19+
if self.len < N {
20+
self.buf[self.len] = b;
21+
self.len += 1;
22+
}
23+
}
24+
Ok(())
25+
}
26+
}
27+
// ----------------------------------------------
428

529
pub struct SysMonitor {
630
info: SystemInfo,
@@ -18,9 +42,9 @@ impl SysMonitor {
1842
}
1943

2044
pub fn draw(&self, fb: &mut [u32], screen_w: usize, screen_h: usize, x: usize, y: usize) {
21-
// Draw Window Background
22-
draw::draw_rect(fb, screen_w, screen_h, x, y, 320, 260, 0xFF181818);
23-
draw::draw_rect(fb, screen_w, screen_h, x, y, 320, 25, 0xFF2A2A2A);
45+
// Draw Window Background (Fixed bounds to match main.rs 300x200)
46+
draw::draw_rect(fb, screen_w, screen_h, x, y, 300, 200, 0xFF181818);
47+
draw::draw_rect(fb, screen_w, screen_h, x, y, 300, 25, 0xFF2A2A2A);
2448
draw::draw_text(fb, screen_w, screen_h, x + 10, y + 5, "NyxOS Live Telemetry", 0xFFFFFFFF);
2549

2650
let mut cy = y + 40;
@@ -29,28 +53,41 @@ impl SysMonitor {
2953
let temp_color = if self.info.current_temp >= 80 { 0xFFFF3333 }
3054
else if self.info.current_temp > 60 { 0xFFFFFF33 }
3155
else { 0xFF33FF33 };
32-
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, &format!("Silicon Temp : {} C", self.info.current_temp), temp_color);
56+
57+
let mut buf = StackString::<64>::new();
58+
let _ = write!(&mut buf, "Silicon Temp : {} C", self.info.current_temp);
59+
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, buf.as_str(), temp_color);
3360
cy += 25;
3461

3562
// 2. LIVE SMM FAN TACHOMETER
36-
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, &format!("CPU Fan Speed: {} RPM", self.info.cpu_fan_rpm), 0xFF00AAFF);
63+
let mut buf = StackString::<64>::new();
64+
let _ = write!(&mut buf, "CPU Fan Speed: {} RPM", self.info.cpu_fan_rpm);
65+
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, buf.as_str(), 0xFF00AAFF);
3766
cy += 20;
38-
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, &format!("GPU Fan Speed: {} RPM", self.info.gpu_fan_rpm), 0xFF00AAFF);
67+
68+
let mut buf = StackString::<64>::new();
69+
let _ = write!(&mut buf, "GPU Fan Speed: {} RPM", self.info.gpu_fan_rpm);
70+
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, buf.as_str(), 0xFF00AAFF);
3971
cy += 25;
4072

4173
// 3. TASK SCHEDULER
42-
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, &format!("Total Tasks : {}", self.info.task_count), 0xFFAAAAAA);
74+
let mut buf = StackString::<64>::new();
75+
let _ = write!(&mut buf, "Total Tasks : {}", self.info.task_count);
76+
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, buf.as_str(), 0xFFAAAAAA);
4377
cy += 20;
4478

45-
draw::draw_rect(fb, screen_w, screen_h, x + 15, cy, 290, 1, 0xFF444444);
79+
draw::draw_rect(fb, screen_w, screen_h, x + 15, cy, 270, 1, 0xFF444444);
4680
cy += 10;
4781

48-
// Render top 5 active tasks
49-
let limit = core::cmp::min(self.info.task_count as usize, 5);
82+
// Render top active tasks
83+
let limit = core::cmp::min(self.info.task_count as usize, 4); // Max 4 to fit in 200px height
5084
for i in 0..limit {
5185
let t = &self.info.tasks[i];
5286
let name = if let Ok(s) = core::str::from_utf8(&t.name) { s.trim_matches(char::from(0)) } else { "Unknown" };
53-
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, &format!("PID {:02} | {} | {} Ticks", t.pid, name, t.cpu_ticks), 0xFF888888);
87+
88+
let mut buf = StackString::<64>::new();
89+
let _ = write!(&mut buf, "PID {:02} | {} | {} Ticks", t.pid, name, t.cpu_ticks);
90+
draw::draw_text(fb, screen_w, screen_h, x + 15, cy, buf.as_str(), 0xFF888888);
5491
cy += 16;
5592
}
5693
}

nyx-user/src/gfx/draw.rs

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub fn draw_text(fb: &mut [u32], w: usize, h: usize, x: usize, y: usize, text: &
3939
cx += font::CHAR_WIDTH;
4040
}
4141
}
42+
4243
/// Draws a filled rectangle on the framebuffer with strict bounds checking.
4344
pub fn draw_rect(
4445
fb: &mut [u32],
@@ -83,7 +84,6 @@ pub fn restore_wallpaper_rect(fb: &mut [u32], w: usize, h: usize, x: usize, y: u
8384
}
8485
}
8586

86-
8787
/// Draws a rounded glass rectangle with a border
8888
pub fn draw_glass_rounded_rect(
8989
fb: &mut [u32],
@@ -95,17 +95,16 @@ pub fn draw_glass_rounded_rect(
9595
alpha: u8
9696
) {
9797
// 1. Blur the background region (Rectangle)
98-
// This creates the "frost" effect.
9998
for _ in 0..3 {
10099
box_blur(fb, screen_w, screen_h, x, y, w, h, 1);
101100
}
102101

103-
let radius_sq = radius * radius;
104102
// Pre-calculate border colors
105-
// Top/Left is brighter (Light source), Bottom/Right is dimmer
106103
let border_light = 0x88FFFFFF;
107104
let border_dark = 0x44FFFFFF;
108105

106+
let r = radius as isize;
107+
109108
// 2. Scan every pixel in the box
110109
for row in 0..h {
111110
let sy = y + row;
@@ -120,37 +119,35 @@ pub fn draw_glass_rounded_rect(
120119
let w_i = w as isize;
121120
let h_i = h as isize;
122121

123-
// --- Rounded Corner Math ---
122+
// --- Rounded Corner Math (Mathematically Safe) ---
124123
let mut in_corner = false;
125124
let mut on_border = false;
126125

127-
// Check Top-Left
128-
if cx < radius && cy < radius {
129-
let d = (radius - cx - 1).pow(2) + (radius - cy - 1).pow(2);
130-
if d > radius_sq { in_corner = true; } // Outside rounded area
131-
else if d >= (radius - 2).pow(2) { on_border = true; } // Edge
132-
}
133-
// Check Top-Right
134-
else if cx >= w_i - radius && cy < radius {
135-
let d = (cx - (w_i - radius)).pow(2) + (radius - cy - 1).pow(2);
136-
if d > radius_sq { in_corner = true; }
137-
else if d >= (radius - 2).pow(2) { on_border = true; }
138-
}
139-
// Check Bottom-Left
140-
else if cx < radius && cy >= h_i - radius {
141-
let d = (radius - cx - 1).pow(2) + (cy - (h_i - radius)).pow(2);
142-
if d > radius_sq { in_corner = true; }
143-
else if d >= (radius - 2).pow(2) { on_border = true; }
144-
}
145-
// Check Bottom-Right
146-
else if cx >= w_i - radius && cy >= h_i - radius {
147-
let d = (cx - (w_i - radius)).pow(2) + (cy - (h_i - radius)).pow(2);
148-
if d > radius_sq { in_corner = true; }
149-
else if d >= (radius - 2).pow(2) { on_border = true; }
150-
}
151-
// Check Straight Edges
152-
else {
153-
if col < 1 || col >= w - 1 || row < 1 || row >= h - 1 { on_border = true; }
126+
let dist_sq = if cx < r && cy < r {
127+
// Top-Left
128+
(r - cx - 1).pow(2) + (r - cy - 1).pow(2)
129+
} else if cx >= w_i - r && cy < r {
130+
// Top-Right
131+
(cx - (w_i - r)).pow(2) + (r - cy - 1).pow(2)
132+
} else if cx < r && cy >= h_i - r {
133+
// Bottom-Left
134+
(r - cx - 1).pow(2) + (cy - (h_i - r)).pow(2)
135+
} else if cx >= w_i - r && cy >= h_i - r {
136+
// Bottom-Right
137+
(cx - (w_i - r)).pow(2) + (cy - (h_i - r)).pow(2)
138+
} else {
139+
// Not near any corner
140+
0
141+
};
142+
143+
if dist_sq > r * r {
144+
in_corner = true;
145+
}
146+
else if dist_sq >= (r - 2).max(0).pow(2) && dist_sq <= r * r {
147+
on_border = true;
148+
}
149+
else if col < 1 || col >= w - 1 || row < 1 || row >= h - 1 {
150+
on_border = true;
154151
}
155152

156153
// 3. Pixel Writing

0 commit comments

Comments
 (0)