+3
-1
.claude/settings.local.json
+3
-1
.claude/settings.local.json
···
81
81
"Bash(cmd /c \"cd /d F:\\OS\\aethelos-source && cargo build 2>&1 | findstr /C:\"Compiling\" /C:\"Finished\" /C:\"error\"\")",
82
82
"Bash(cargo doc:*)",
83
83
"Bash(cmd /c \"cd /d F:\\OS\\aethelos-source && taskkill /F /IM qemu-system-x86_64.exe 2>nul & cd /d F:\\OS\\aethelos-source & del serial.log 2>nul & start /B \"\" \"C:Program Filesqemuqemu-system-x86_64.exe\" -cdrom aethelos.iso -serial file:serial.log -m 256M -display gtk -no-reboot -no-shutdown\")",
84
-
"Bash(cmd /c \"cd /d F:\\OS\\aethelos-source && taskkill /F /IM qemu-system-x86_64.exe 2>nul & del serial.log 2>nul & start /B \"\" \"C:Program Filesqemuqemu-system-x86_64.exe\" -cdrom aethelos.iso -serial file:serial.log -m 256M -display gtk -no-reboot -no-shutdown\")"
84
+
"Bash(cmd /c \"cd /d F:\\OS\\aethelos-source && taskkill /F /IM qemu-system-x86_64.exe 2>nul & del serial.log 2>nul & start /B \"\" \"C:Program Filesqemuqemu-system-x86_64.exe\" -cdrom aethelos.iso -serial file:serial.log -m 256M -display gtk -no-reboot -no-shutdown\")",
85
+
"Bash(cargo fix:*)",
86
+
"Bash(tee:*)"
85
87
],
86
88
"deny": [],
87
89
"ask": []
-6
aethelos-source/heartwood/Cargo.toml
-6
aethelos-source/heartwood/Cargo.toml
+2
-2
aethelos-source/heartwood/src/attunement/keyboard.rs
+2
-2
aethelos-source/heartwood/src/attunement/keyboard.rs
···
35
35
unsafe {
36
36
let keyboard = Keyboard::new();
37
37
let lock = InterruptSafeLock::new(keyboard);
38
-
core::ptr::write(KEYBOARD.as_mut_ptr(), lock);
38
+
core::ptr::write(core::ptr::addr_of_mut!(KEYBOARD).cast(), lock);
39
39
KEYBOARD_INITIALIZED = true;
40
40
}
41
41
}
···
47
47
return;
48
48
}
49
49
50
-
let mut keyboard = (*KEYBOARD.as_ptr()).lock();
50
+
let mut keyboard = (*core::ptr::addr_of!(KEYBOARD).cast::<InterruptSafeLock<Keyboard>>()).lock();
51
51
let scancode = keyboard.read_scancode();
52
52
53
53
// Ignore key release events (scancode >= 0x80)
-1
aethelos-source/heartwood/src/boot/boot32.rs
-1
aethelos-source/heartwood/src/boot/boot32.rs
-2
aethelos-source/heartwood/src/boot/multiboot2.rs
-2
aethelos-source/heartwood/src/boot/multiboot2.rs
···
8
8
//! This is the handshake between bootloader and kernel - the first
9
9
//! moment of trust between two systems working together.
10
10
11
-
use core::arch::global_asm;
12
-
13
11
/// Multiboot2 magic number
14
12
/// Bootloaders look for this to identify our kernel
15
13
pub const MULTIBOOT2_MAGIC: u32 = 0xE85250D6;
+60
-21
aethelos-source/heartwood/src/eldarin.rs
+60
-21
aethelos-source/heartwood/src/eldarin.rs
···
9
9
//! The shell does not merely execute - it interprets, validates, and responds
10
10
//! with both action and wisdom.
11
11
12
-
use core::fmt::Write;
13
12
use crate::mana_pool::InterruptSafeLock;
14
13
use core::mem::MaybeUninit;
15
14
···
191
190
unsafe {
192
191
let buffer = CommandBuffer::new();
193
192
let lock = InterruptSafeLock::new(buffer);
194
-
core::ptr::write(COMMAND_BUFFER.as_mut_ptr(), lock);
193
+
core::ptr::write(core::ptr::addr_of_mut!(COMMAND_BUFFER).cast(), lock);
195
194
BUFFER_INITIALIZED = true;
196
195
197
196
let history = CommandHistory::new();
198
197
let history_lock = InterruptSafeLock::new(history);
199
-
core::ptr::write(COMMAND_HISTORY.as_mut_ptr(), history_lock);
198
+
core::ptr::write(core::ptr::addr_of_mut!(COMMAND_HISTORY).cast(), history_lock);
200
199
HISTORY_INITIALIZED = true;
201
200
}
202
201
}
203
202
204
203
/// Get reference to command buffer
205
204
unsafe fn get_buffer() -> &'static InterruptSafeLock<CommandBuffer> {
206
-
COMMAND_BUFFER.assume_init_ref()
205
+
&*core::ptr::addr_of!(COMMAND_BUFFER).cast::<InterruptSafeLock<CommandBuffer>>()
207
206
}
208
207
209
208
/// Get reference to command history
210
209
unsafe fn get_history() -> &'static InterruptSafeLock<CommandHistory> {
211
-
COMMAND_HISTORY.assume_init_ref()
210
+
&*core::ptr::addr_of!(COMMAND_HISTORY).cast::<InterruptSafeLock<CommandHistory>>()
212
211
}
213
212
214
213
/// Handle a character from keyboard input
···
328
327
let has_newline = buffer.as_str().contains('\n');
329
328
if has_newline {
330
329
// Debug: we found a newline!
331
-
let mut port = 0x3f8u16;
330
+
let port = 0x3f8u16;
332
331
core::arch::asm!(
333
332
"out dx, al",
334
333
in("dx") port,
···
382
381
pub fn display_prompt() {
383
382
// Debug: signal that we're about to print prompt
384
383
unsafe {
385
-
let mut port = 0x3f8u16;
384
+
let port = 0x3f8u16;
386
385
core::arch::asm!(
387
386
"out dx, al",
388
387
in("dx") port,
···
592
591
0
593
592
};
594
593
595
-
// Draw a beautiful progress bar
596
-
crate::println!(" Total Essence: {} KB", total_kb);
597
-
crate::println!();
598
-
crate::print!(" [");
594
+
// Sanctuary Pool (Persistent Memory)
595
+
crate::println!(" Sanctuary Pool (Persistent):");
596
+
crate::println!(" Total: {} KB", sanctuary_total_kb);
597
+
crate::println!(" Used: {} KB", sanctuary_used_kb);
598
+
crate::println!(" Free: {} KB", sanctuary_free_kb);
599
599
600
-
let bar_width = 50;
601
-
let filled = (used_percent as usize * bar_width) / 100;
600
+
// Draw sanctuary progress bar
601
+
let sanctuary_percent = if stats.sanctuary_total > 0 {
602
+
(stats.sanctuary_used * 100) / stats.sanctuary_total
603
+
} else {
604
+
0
605
+
};
606
+
crate::print!(" [");
607
+
let bar_width = 40;
608
+
let filled = (sanctuary_percent as usize * bar_width) / 100;
602
609
for i in 0..bar_width {
603
610
if i < filled {
604
611
crate::print!("█");
···
606
613
crate::print!("░");
607
614
}
608
615
}
609
-
crate::println!("] {}%", used_percent);
616
+
crate::println!("] {}%", sanctuary_percent);
610
617
crate::println!();
611
618
612
-
crate::println!(" Sustenance (Used): {} KB", used_kb);
613
-
crate::println!(" Free Flow (Available): {} KB", free_kb);
619
+
// Ephemeral Pool (Temporary Memory)
620
+
crate::println!(" Ephemeral Mist (Temporary):");
621
+
crate::println!(" Total: {} KB", ephemeral_total_kb);
622
+
crate::println!(" Used: {} KB", ephemeral_used_kb);
623
+
crate::println!(" Free: {} KB", ephemeral_free_kb);
624
+
625
+
// Draw ephemeral progress bar
626
+
let ephemeral_percent = if stats.ephemeral_total > 0 {
627
+
(stats.ephemeral_used * 100) / stats.ephemeral_total
628
+
} else {
629
+
0
630
+
};
631
+
crate::print!(" [");
632
+
let filled = (ephemeral_percent as usize * bar_width) / 100;
633
+
for i in 0..bar_width {
634
+
if i < filled {
635
+
crate::print!("█");
636
+
} else {
637
+
crate::print!("░");
638
+
}
639
+
}
640
+
crate::println!("] {}%", ephemeral_percent);
614
641
crate::println!();
615
642
616
-
crate::println!(" Sanctuary (Long-lived):");
617
-
crate::println!(" Used: {} KB / {} KB", sanctuary_used_kb, sanctuary_total_kb);
618
-
crate::println!();
643
+
// Overall Summary
644
+
crate::println!(" Overall Summary:");
645
+
crate::println!(" Total: {} KB", total_kb);
646
+
crate::println!(" Used: {} KB", used_kb);
647
+
crate::println!(" Free: {} KB", free_kb);
619
648
620
-
crate::println!(" Ephemeral Mist (Short-lived):");
621
-
crate::println!(" Used: {} KB / {} KB", ephemeral_used_kb, ephemeral_total_kb);
649
+
// Draw total progress bar
650
+
crate::print!(" [");
651
+
let bar_width = 40;
652
+
let filled = (used_percent as usize * bar_width) / 100;
653
+
for i in 0..bar_width {
654
+
if i < filled {
655
+
crate::print!("█");
656
+
} else {
657
+
crate::print!("░");
658
+
}
659
+
}
660
+
crate::println!("] {}%", used_percent);
622
661
crate::println!();
623
662
624
663
crate::println!(" Total Objects: {}", stats.total_objects);
+1
-1
aethelos-source/heartwood/src/irq_safe_mutex.rs
+1
-1
aethelos-source/heartwood/src/irq_safe_mutex.rs
+1
-1
aethelos-source/heartwood/src/loom_of_fate/context.rs
+1
-1
aethelos-source/heartwood/src/loom_of_fate/context.rs
···
436
436
///
437
437
/// This function is called when a new thread is first scheduled.
438
438
/// It handles any setup needed before calling the actual entry point.
439
-
pub extern "C" fn thread_entry_wrapper(entry_point: fn() -> !) -> ! {
439
+
pub extern "C" fn thread_entry_wrapper(entry_point: extern "C" fn() -> !) -> ! {
440
440
// Enable interrupts for this new thread
441
441
unsafe {
442
442
asm!("sti", options(nomem, nostack));
+2
-2
aethelos-source/heartwood/src/loom_of_fate/mod.rs
+2
-2
aethelos-source/heartwood/src/loom_of_fate/mod.rs
···
69
69
serial_out(b'D'); // InterruptSafeLock created
70
70
71
71
// Write the small InterruptSafeLock<Box<Scheduler>> to static
72
-
core::ptr::write(LOOM.as_mut_ptr(), lock);
72
+
core::ptr::write(core::ptr::addr_of_mut!(LOOM).cast(), lock);
73
73
serial_out(b'y'); // Written to MaybeUninit
74
74
75
75
LOOM_INITIALIZED = true;
···
110
110
/// # Safety
111
111
/// LOOM must be initialized before calling this function
112
112
pub unsafe fn get_loom() -> &'static InterruptSafeLock<Box<Scheduler>> {
113
-
LOOM.assume_init_ref()
113
+
&*core::ptr::addr_of!(LOOM).cast::<InterruptSafeLock<Box<Scheduler>>>()
114
114
}
115
115
116
116
/// Spawn a new thread
+12
-2
aethelos-source/heartwood/src/loom_of_fate/scheduler.rs
+12
-2
aethelos-source/heartwood/src/loom_of_fate/scheduler.rs
···
54
54
55
55
// Pre-allocate capacity to prevent reallocation during push
56
56
// This avoids memory overlap between Vec storage and stack allocations
57
-
let mut threads = Vec::with_capacity(16);
57
+
let threads = Vec::with_capacity(16);
58
58
unsafe { serial_out(b'b'); } // threads Vec created
59
-
let mut stacks = Vec::with_capacity(16);
59
+
let stacks = Vec::with_capacity(16);
60
60
unsafe { serial_out(b'c'); } // stacks Vec created
61
61
let ready_queue = VecDeque::new();
62
62
unsafe { serial_out(b'd'); } // ready_queue created
···
250
250
///
251
251
/// # Safety
252
252
/// Assumes both thread IDs are valid and the threads exist
253
+
///
254
+
/// Note: This is an old implementation from preemptive scheduling experiments.
255
+
/// The system now uses a different approach (cooperative + interrupt-based).
256
+
/// Kept as reference for alternative scheduling strategies.
257
+
#[allow(dead_code)]
253
258
fn perform_context_switch(&mut self, from_id: ThreadId, to_id: ThreadId) {
254
259
// Get raw pointers to the contexts before borrowing
255
260
let from_idx = self.threads.iter().position(|t| t.id() == from_id).unwrap();
···
276
281
///
277
282
/// # Safety
278
283
/// This function never returns normally - it restores the thread's context
284
+
///
285
+
/// Note: Old implementation from preemptive scheduling experiments.
286
+
/// Current system uses context::context_switch_first() instead.
287
+
/// Kept as reference for alternative boot strategies.
288
+
#[allow(dead_code)]
279
289
fn restore_first_thread(&mut self, to_id: ThreadId) -> ! {
280
290
// Find the thread's context
281
291
let to_idx = self.threads.iter().position(|t| t.id() == to_id).unwrap();
+4
-4
aethelos-source/heartwood/src/loom_of_fate/system_threads.rs
+4
-4
aethelos-source/heartwood/src/loom_of_fate/system_threads.rs
···
10
10
//! The keyboard thread listens attentively to user intentions.
11
11
//! The shell thread translates human wishes into system actions.
12
12
13
-
use super::{ThreadPriority, yield_now};
13
+
use super::yield_now;
14
14
15
15
/// The Idle Thread - The First Awakening
16
16
///
···
32
32
33
33
// DEBUG: Silent marker that we've awakened
34
34
unsafe {
35
-
let mut port = 0x3f8u16;
35
+
let port = 0x3f8u16;
36
36
core::arch::asm!(
37
37
"out dx, al",
38
38
in("dx") port,
···
65
65
66
66
// DEBUG: Interrupts enabled
67
67
unsafe {
68
-
let mut port = 0x3f8u16;
68
+
let port = 0x3f8u16;
69
69
core::arch::asm!(
70
70
"out dx, al",
71
71
in("dx") port,
···
191
191
);
192
192
let interrupts_enabled = (flags & 0x200) != 0;
193
193
194
-
let mut port = 0x3f8u16;
194
+
let port = 0x3f8u16;
195
195
core::arch::asm!(
196
196
"out dx, al",
197
197
in("dx") port,
+7
aethelos-source/heartwood/src/loom_of_fate/thread.rs
+7
aethelos-source/heartwood/src/loom_of_fate/thread.rs
···
37
37
pub(crate) id: ThreadId,
38
38
pub(crate) state: ThreadState,
39
39
pub(crate) priority: ThreadPriority,
40
+
41
+
/// Entry point function - kept for debugging/inspection
42
+
#[allow(dead_code)]
40
43
pub(crate) entry_point: fn() -> !,
41
44
42
45
// CPU state (for context switching)
43
46
pub(crate) context: ThreadContext,
47
+
48
+
/// Stack boundaries - kept for future stack overflow detection
49
+
#[allow(dead_code)]
44
50
pub(crate) stack_bottom: u64,
51
+
#[allow(dead_code)]
45
52
pub(crate) stack_top: u64,
46
53
47
54
// Harmony tracking
+6
-2
aethelos-source/heartwood/src/main.rs
+6
-2
aethelos-source/heartwood/src/main.rs
···
15
15
extern crate alloc;
16
16
17
17
// Reference the modules from lib.rs
18
-
use heartwood::{nexus, loom_of_fate, mana_pool, attunement, vga_buffer};
18
+
use heartwood::{nexus, loom_of_fate, mana_pool, attunement};
19
19
20
20
// Need to use macros with #[macro_use]
21
21
#[macro_use]
···
101
101
}
102
102
103
103
// UNREACHABLE - the bootstrap ghost is gone
104
-
unreachable!("The Great Hand-Off should never return")
104
+
// This is intentional defensive programming to document the expected behavior
105
+
#[allow(unreachable_code)]
106
+
{
107
+
unreachable!("The Great Hand-Off should never return")
108
+
}
105
109
}
106
110
107
111
/// Initialize the Heartwood's core systems
+1
-1
aethelos-source/heartwood/src/mana_pool/buddy.rs
+1
-1
aethelos-source/heartwood/src/mana_pool/buddy.rs
···
210
210
/// unused parts to the appropriate free lists
211
211
fn split_block(&mut self, block: NonNull<Block>, current_order: usize, target_order: usize) {
212
212
let mut order = current_order;
213
-
let mut addr = block.as_ptr() as usize;
213
+
let addr = block.as_ptr() as usize;
214
214
215
215
while order > target_order {
216
216
order -= 1;
+1
-1
aethelos-source/heartwood/src/mana_pool/interrupt_lock.rs
+1
-1
aethelos-source/heartwood/src/mana_pool/interrupt_lock.rs
···
33
33
}
34
34
35
35
/// Acquire the lock, returning a guard that restores interrupt state on drop
36
-
pub fn lock(&self) -> InterruptSafeLockGuard<T> {
36
+
pub fn lock(&self) -> InterruptSafeLockGuard<'_, T> {
37
37
// Save current interrupt state
38
38
let interrupts_enabled = are_interrupts_enabled();
39
39
+2
-2
aethelos-source/heartwood/src/mana_pool/mod.rs
+2
-2
aethelos-source/heartwood/src/mana_pool/mod.rs
···
174
174
let lock = InterruptSafeLock::new(mana_pool_on_heap);
175
175
serial_out(b'Q'); // After InterruptSafeLock::new
176
176
177
-
core::ptr::write(MANA_POOL.as_mut_ptr(), lock);
177
+
core::ptr::write(core::ptr::addr_of_mut!(MANA_POOL).cast(), lock);
178
178
serial_out(b'R'); // Written to static
179
179
180
180
MANA_POOL_INITIALIZED = true;
···
184
184
185
185
/// Get reference to MANA_POOL (assumes initialized)
186
186
unsafe fn get_mana_pool() -> &'static InterruptSafeLock<Box<ManaPool>> {
187
-
MANA_POOL.assume_init_ref()
187
+
&*core::ptr::addr_of!(MANA_POOL).cast::<InterruptSafeLock<Box<ManaPool>>>()
188
188
}
189
189
190
190
/// Allocate memory with a specific purpose
+2
aethelos-source/heartwood/src/mana_pool/object_manager.rs
+2
aethelos-source/heartwood/src/mana_pool/object_manager.rs
+2
-2
aethelos-source/heartwood/src/nexus/mod.rs
+2
-2
aethelos-source/heartwood/src/nexus/mod.rs
···
52
52
let lock = InterruptSafeLock::new(nexus_core);
53
53
serial_out(b'u'); // After InterruptSafeLock::new
54
54
55
-
core::ptr::write(NEXUS.as_mut_ptr(), lock);
55
+
core::ptr::write(core::ptr::addr_of_mut!(NEXUS).cast(), lock);
56
56
serial_out(b'!'); // Written to static
57
57
58
58
NEXUS_INITIALIZED = true;
···
61
61
62
62
/// Get reference to NEXUS (assumes initialized)
63
63
unsafe fn get_nexus() -> &'static InterruptSafeLock<NexusCore> {
64
-
NEXUS.assume_init_ref()
64
+
&*core::ptr::addr_of!(NEXUS).cast::<InterruptSafeLock<NexusCore>>()
65
65
}
66
66
67
67
/// Send a message through the Nexus
+5
-61
aethelos-source/heartwood/src/vga_buffer.rs
+5
-61
aethelos-source/heartwood/src/vga_buffer.rs
···
242
242
243
243
// Wrap in IRQ-safe mutex and write to static
244
244
let mutex = IrqSafeMutex::new(writer);
245
-
core::ptr::write(WRITER.as_mut_ptr(), mutex);
245
+
core::ptr::write(core::ptr::addr_of_mut!(WRITER).cast(), mutex);
246
246
WRITER_INITIALIZED = true;
247
247
248
248
// Clear the screen
249
-
let mut writer = WRITER.assume_init_mut().lock();
249
+
let mut writer = (*core::ptr::addr_of_mut!(WRITER).cast::<IrqSafeMutex<Writer>>()).lock();
250
250
for row in 0..BUFFER_HEIGHT {
251
251
writer.clear_row(row);
252
252
}
···
258
258
259
259
/// Get reference to WRITER (assumes initialized)
260
260
unsafe fn get_writer() -> &'static IrqSafeMutex<Writer> {
261
-
WRITER.assume_init_ref()
261
+
&*core::ptr::addr_of!(WRITER).cast::<IrqSafeMutex<Writer>>()
262
262
}
263
263
264
264
/// Force unlock the VGA writer (for use before context switches)
···
268
268
/// no other code will try to use the lock.
269
269
pub unsafe fn force_unlock() {
270
270
if WRITER_INITIALIZED {
271
-
let writer = WRITER.assume_init_mut();
271
+
let writer = &mut *core::ptr::addr_of_mut!(WRITER).cast::<IrqSafeMutex<Writer>>();
272
272
writer.force_unlock();
273
273
}
274
274
}
···
282
282
}
283
283
284
284
// Get raw pointer to the writer inside the IRQ-safe mutex
285
-
let writer_ptr = WRITER.as_ptr() as *mut IrqSafeMutex<Writer>;
285
+
let writer_ptr = core::ptr::addr_of_mut!(WRITER).cast::<IrqSafeMutex<Writer>>();
286
286
// Access the inner Mutex to get the data (unsafe pointer dereference)
287
287
let inner_mutex = &mut (*writer_ptr).inner;
288
288
let writer = inner_mutex.get_mut();
···
392
392
}
393
393
}
394
394
}
395
-
396
-
/// Execute a closure with interrupts disabled
397
-
/// This prevents deadlocks when acquiring locks that might be used in interrupt handlers
398
-
fn without_interrupts<F, R>(f: F) -> R
399
-
where
400
-
F: FnOnce() -> R,
401
-
{
402
-
// Check if interrupts are currently enabled
403
-
let were_enabled: bool;
404
-
unsafe {
405
-
let flags: u64;
406
-
core::arch::asm!(
407
-
"pushfq",
408
-
"pop {0}",
409
-
out(reg) flags,
410
-
options(nomem, preserves_flags)
411
-
);
412
-
were_enabled = (flags & 0x200) != 0;
413
-
}
414
-
415
-
// Disable interrupts
416
-
unsafe {
417
-
core::arch::asm!("cli", options(nomem, nostack, preserves_flags));
418
-
}
419
-
420
-
// Execute the closure
421
-
let result = f();
422
-
423
-
// Only re-enable if they were enabled before
424
-
// This prevents re-enabling interrupts during early boot
425
-
if were_enabled {
426
-
unsafe {
427
-
core::arch::asm!("sti", options(nomem, nostack, preserves_flags));
428
-
429
-
// Debug: output to serial that we re-enabled interrupts
430
-
core::arch::asm!(
431
-
"mov dx, 0x3f8",
432
-
"mov al, 0x2B", // '+' = re-enabled
433
-
"out dx, al",
434
-
options(nomem, nostack, preserves_flags)
435
-
);
436
-
}
437
-
} else {
438
-
unsafe {
439
-
// Debug: output that we DIDN'T re-enable
440
-
core::arch::asm!(
441
-
"mov dx, 0x3f8",
442
-
"mov al, 0x2D", // '-' = stayed disabled
443
-
"out dx, al",
444
-
options(nomem, nostack, preserves_flags)
445
-
);
446
-
}
447
-
}
448
-
449
-
result
450
-
}