From 8b026ce96c614adc4e525c24cf24c5e51ae42b59 Mon Sep 17 00:00:00 2001 From: Yash-Rawat-IIT-D Date: Wed, 4 Mar 2026 21:26:52 +0000 Subject: [PATCH 1/3] First process execution --- .gdbinit.tmpl | 2 +- Makefile | 12 ++- initcode.S | 10 ++ linkers/kernel.ld | 2 +- src/console.rs | 1 + src/constants.rs | 26 +++++- src/lapic.rs | 9 +- src/lib.rs | 30 ++++-- src/param.rs | 2 + src/proc.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++-- src/spinlock.rs | 32 +++++++ src/vm.rs | 6 +- src/x86.rs | 78 ++++++++++++++++ swtch.S | 22 +++++ trapasm.S | 13 +++ 15 files changed, 443 insertions(+), 29 deletions(-) create mode 100644 initcode.S create mode 100644 src/spinlock.rs create mode 100644 swtch.S diff --git a/.gdbinit.tmpl b/.gdbinit.tmpl index 1dfd173..ca8444b 100644 --- a/.gdbinit.tmpl +++ b/.gdbinit.tmpl @@ -25,4 +25,4 @@ target remote localhost:1234 echo + symbol-file kernel\n symbol-file kernel -layout split \ No newline at end of file +# layout split \ No newline at end of file diff --git a/Makefile b/Makefile index c4a3ef4..90424f4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -OBJS = entry.o vectors.o trapasm.o +OBJS = entry.o vectors.o trapasm.o swtch.o RS = src/*.rs # Cross-compiling (e.g., on Mac OS X) @@ -70,6 +70,12 @@ bootblock: bootasm.S bootmain.c linkers/bootblock.ld $(OBJDUMP) -S bootblock.o > bootblock.asm $(OBJCOPY) -S -O binary bootblock.o bootblock +initcode: initcode.S + $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S + $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o + $(OBJCOPY) -S -O binary initcode.out initcode + $(OBJDUMP) -S initcode.o > initcode.asm + kernel.a: $(RS) cargo build -Z build-std=core -Z build-std-features=compiler-builtins-mem -Z json-target-spec \ --target ./targets/i686.json --release @@ -79,8 +85,8 @@ kernel.a: $(RS) cp "$$lib" kernel.a -kernel: kernel.a $(OBJS) ./linkers/kernel.ld - $(LD) -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a +kernel: kernel.a $(OBJS) ./linkers/kernel.ld initcode + $(LD) -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a -b binary initcode $(OBJDUMP) -S -D kernel > kernel.asm $(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym diff --git a/initcode.S b/initcode.S new file mode 100644 index 0000000..ea554dc --- /dev/null +++ b/initcode.S @@ -0,0 +1,10 @@ +# Initial process execs /init. +# This code runs in user space. + +# movl %eax, 0x10001 +# movl %eax, 0x1000100 +.globl start +start: + add $1, %eax + movl %eax, 0x10001 + jmp start diff --git a/linkers/kernel.ld b/linkers/kernel.ld index cf6630e..0b70493 100644 --- a/linkers/kernel.ld +++ b/linkers/kernel.ld @@ -8,7 +8,7 @@ ENTRY(_start) SECTIONS { /* Link the kernel at this address: "." means the current address */ - /* Must be equal to KERNLINK */ + /* Must be equal to KERNLINK */ . = 0x00100000; .text : AT(0x100000) { diff --git a/src/console.rs b/src/console.rs index 7ad6727..61d9302 100644 --- a/src/console.rs +++ b/src/console.rs @@ -76,6 +76,7 @@ pub fn consoleintr(getc: fn() -> i32) { (*input).e += 1; consputc(c); if c == '\n' as i32 || c == CTRL_D || (*input).e == (*input).r + INPUT_BUF { + // call myproc with the buf (*input).w = (*input).e; } } diff --git a/src/constants.rs b/src/constants.rs index f7dd337..44dae04 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,15 +15,39 @@ pub const SEG_TSS: u16 = 5; // this process's task state // cpu->gdt[NSEGS] holds the above segments. pub const NSEGS: usize = 6; +// Privilege level +pub const DPL_USER: u8 = 0x3; // User DPL + // Application segment type bits pub const STA_X: u8 = 0x8; // Executable segment pub const STA_W: u8 = 0x2; // Writeable (non-executable segments) pub const STA_R: u8 = 0x2; // Readable (executable segments) // Memory layout +pub const EXTMEM: u32 = 0x100000; // Start of extended memory +pub const PHYSTOP: u32 = 0xE000000; // Top physical memory +pub const DEVSPACE: u32 = 0xFE000000; // Other devices are at high addresses + +// Key addresses for address space layout +pub const KERNBASE: u32 = 0x0; // First kernel virtual address +pub const KERNLINK: u32 = KERNBASE + EXTMEM; // Address where kernel is linked + // We assume that kernel.asm can fit in first 2MB pub const STARTPROC: u32 = 0x200000; // Start allocating process from here (2MB) -pub const PROCSIZE: u32 = 0x100000; // Size of each process (1MB) +pub const PROCSIZE: u32 = 0x100; // 1MB is the size of each process (in multiple of 4KB) + +// Page table constants +pub const PGSIZE: u32 = 4096; // bytes mapped by a page +pub const NPDENTRIES: usize = 1024; // # directory entries per page directory +pub const NPTENTRIES: usize = 1024; // # PTEs per page table +pub const PTXSHIFT: u32 = 12; // offset of PTX in a linear address +pub const PDXSHIFT: u32 = 22; // offset of PDX in a linear address + +// Page table/directory entry flags +pub const PTE_P: u32 = 0x001; // Present +pub const PTE_W: u32 = 0x002; // Writeable +pub const PTE_U: u32 = 0x004; // User +pub const PTE_PS: u32 = 0x080; // Page Size // System segment type bits pub const STS_T32A: u8 = 0x9; // Available 32-bit TSS diff --git a/src/lapic.rs b/src/lapic.rs index fc3dbca..5612dbb 100644 --- a/src/lapic.rs +++ b/src/lapic.rs @@ -1,6 +1,6 @@ use core::ptr::{read_volatile, write_volatile}; use crate::mp::MP_ONCE; -use crate::constants::{IRQ_ERROR, IRQ_SPURIOUS, IRQ_TIMER, T_IRQ0}; +use crate::constants::{IRQ_ERROR, IRQ_SPURIOUS, T_IRQ0}; const ID: isize = 0x0020 / 4; const VER: isize = 0x0030 / 4; @@ -68,9 +68,10 @@ pub fn lapicinit() { // from lapic[TICR] and then issues an interrupt. // If xv6 cared more about precise timekeeping, // TICR would be calibrated using an external time source. - lapicw(TDCR, X1); - lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); - lapicw(TICR, 10000000); + // Timer disabled for p15 - will be re-enabled later + // lapicw(TDCR, X1); + // lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); + // lapicw(TICR, 10000000); // Disable logical interrupt lines. diff --git a/src/lib.rs b/src/lib.rs index a318bef..f66304b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ mod file; mod log; mod mmu; mod vm; +mod spinlock; use crate::traps::*; #[macro_export] @@ -102,22 +103,37 @@ pub extern "C" fn entryofrust() -> ! { log::initlog(param::ROOTDEV); file::mknod("/console", param::CONSOLE as i16, param::CONSOLE as i16); vm::seginit(); // segment descriptors - welcome(); - - loop { - x86::wfi(); - } + proc::pinit(); // first process + proc::scheduler(); // start running processes (never returns) } static mut PANICKED: bool = false; #[panic_handler] fn panic(info: &PanicInfo) -> ! { + use core::fmt::Write; + // Disable interrupts to prevent interrupt handlers from interfering cli(); + // Print panic message with LAPIC ID to identify which CPU panicked - println!("lapicid {}:\n{:#?}", lapicid(), info); + let mut console = console::Console {}; + let _ = write!(&mut console, "lapicid {}: panic: ", lapicid()); + let _ = writeln!(&mut console, "{}", info); + + // Print stack trace + let mut pcs = [0u32; 10]; + let stack_ptr = &info as *const _ as *const u32; + spinlock::getcallerpcs(stack_ptr, &mut pcs); + + for &pc in &pcs { + if pc != 0 { + let _ = writeln!(&mut console, " {:#x}", pc); + } + } + unsafe { PANICKED = true; } + // Halt the system - loop {} + halt(); } diff --git a/src/param.rs b/src/param.rs index 4a269c3..2b4ebc4 100644 --- a/src/param.rs +++ b/src/param.rs @@ -1,6 +1,8 @@ +pub const NPROC: usize = 64; // maximum number of processes pub const KSTACKSIZE: usize = 4096; // size of per-process kernel stack (unused in p3) pub const NCPU: usize = 8; // maximum number of CPUs pub const MAXOPBLOCKS: usize = 10; // max # of blocks any FS op writes +pub const NOFILE: usize = 16; // open files per process pub const NFILE: usize = 100; // open files per system pub const NINODE: usize = 50; // maximum number of active i-nodes pub const NDEV: usize = 10; // maximum major device number diff --git a/src/proc.rs b/src/proc.rs index 44c0fad..460baed 100644 --- a/src/proc.rs +++ b/src/proc.rs @@ -1,29 +1,238 @@ -use crate::mp::MP_ONCE; // Import the MP_ONCE static from mp.rs -// use core::ptr; -use crate::constants::NSEGS; +use crate::mp::MP_ONCE; +use crate::constants::{NSEGS, SEG_UCODE, SEG_UDATA, DPL_USER, FL_IF, PGSIZE, STARTPROC, PROCSIZE}; use crate::mmu::SegDesc; +use crate::x86::TrapFrame; +use crate::param::NPROC; +use core::ptr::null_mut; +use core::cell::OnceCell; + +// Saved registers for kernel context switches. +// Don't need to save all the segment registers (%cs, etc), +// because they are constant across kernel contexts. +// Don't need to save %eax, %ecx, %edx, because the +// x86 convention is that the caller has saved them. +// Contexts are stored at the bottom of the stack they +// describe; the stack pointer is the address of the context. +// The layout of the context matches the layout of the stack in swtch.S +// at the "Switch stacks" comment. Switch doesn't save eip explicitly, +// but it is on the stack and allocproc() manipulates it. +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct Context { + pub edi: u32, + pub esi: u32, + pub ebx: u32, + pub ebp: u32, + pub eip: u32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ProcState { + Unused, + Embryo, + Runnable, + Running, +} + +// Per-process state +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Proc { + pub kstack: *mut u8, // Bottom of kernel stack for this process (unused for now) + pub state: ProcState, // Process state + pub pid: i32, // Process ID + pub parent: *mut Proc, // Parent process + pub tf: *mut TrapFrame, // Trap frame for current syscall + pub context: *mut Context, // swtch() here to run process + pub cwd: usize, // Current directory (inode number) + pub name: [u8; 16], // Process name (debugging) +} + +impl Proc { + pub const fn new() -> Self { + Self { + kstack: null_mut(), + state: ProcState::Unused, + pid: 0, + parent: null_mut(), + tf: null_mut(), + context: null_mut(), + cwd: 0, + name: [0; 16], + } + } +} + +// Process table +struct PTable { + proc: [Proc; NPROC], +} + +static mut PTABLE: OnceCell = OnceCell::new(); +static mut NEXTPID: i32 = 1; #[derive(Debug, Clone, Copy)] pub struct Cpu { - pub apicid: u8, // Local APIC ID - pub gdt: [SegDesc; NSEGS], // x86 global descriptor table + pub apicid: u8, // Local APIC ID + pub scheduler: *mut Context, // swtch() here to enter scheduler + pub gdt: [SegDesc; NSEGS], // x86 global descriptor table + pub proc: *mut Proc, // The process running on this cpu or null } impl Cpu { pub const fn new() -> Self { Self { apicid: 0, + scheduler: null_mut(), gdt: [SegDesc::new(); NSEGS], + proc: null_mut(), } } } pub fn cpuid() -> usize { - let cpus = MP_ONCE.cpus.get().expect("CPUs not initialized"); - unsafe { (mycpu() as *const Cpu).offset_from(cpus.as_ptr()) as usize } + // For now, always return 0 (single CPU) + 0 } -pub fn mycpu() -> &'static Cpu { +pub fn mycpu() -> &'static mut Cpu { let cpus = MP_ONCE.cpus.get().expect("CPUs not initialized"); - &cpus[0] + unsafe { &mut *(cpus.as_ptr() as *mut Cpu).add(cpuid()) } +} + +// Read proc from the cpu structure +pub fn myproc() -> Option<&'static mut Proc> { + let c = mycpu(); + if c.proc.is_null() { + None + } else { + Some(unsafe { &mut *c.proc }) + } +} + +// External symbols from assembly +extern "C" { + fn trapret(); + pub fn swtch(context: *mut Context); +} + +// Look in the process table for an UNUSED proc. +// If found, change state to EMBRYO and initialize +// state required to run in the kernel. +// Otherwise return None. +fn allocproc() -> Option<&'static mut Proc> { + unsafe { + let ptable_ptr = core::ptr::addr_of_mut!(PTABLE); + + if (*ptable_ptr).get().is_none() { + let _ = (*ptable_ptr).set(PTable { + proc: [Proc::new(); NPROC], + }); + } + + let ptable = (*ptable_ptr).get_mut().unwrap(); + + for p in &mut ptable.proc { + if p.state == ProcState::Unused { + // Found an unused process + p.state = ProcState::Embryo; + p.pid = NEXTPID; + NEXTPID += 1; + + // Calculate stack pointer at the end of process memory + let sp = (STARTPROC + (PROCSIZE << 12)) as *mut u8; + + // Leave room for trap frame + let sp = sp.sub(core::mem::size_of::()); + p.tf = sp as *mut TrapFrame; + + // Leave room for context + let sp = sp.sub(core::mem::size_of::()); + p.context = sp as *mut Context; + + // Initialize context + core::ptr::write_bytes(p.context, 0, 1); + (*p.context).eip = trapret as *const () as usize as u32; + + return Some(p); + } + } + + None + } +} + +// Set up first process. +pub fn pinit() { + unsafe { + extern "C" { + static _binary_initcode_start: u8; + static _binary_initcode_size: usize; + } + + let p = allocproc().expect("Failed to allocate first process"); + + // Copy initcode binary to STARTPROC + let dst = STARTPROC as *mut u8; + let src = &_binary_initcode_start as *const u8; + let size = &_binary_initcode_size as *const usize as usize; + core::ptr::copy_nonoverlapping(src, dst, size); + + // Initialize trapframe + core::ptr::write_bytes(p.tf, 0, 1); + + (*p.tf).cs = ((SEG_UCODE << 3) | DPL_USER as u16) as u16; + (*p.tf).ds = ((SEG_UDATA << 3) | DPL_USER as u16) as u16; + (*p.tf).es = (*p.tf).ds; + (*p.tf).ss = (*p.tf).ds; + (*p.tf).eflags = FL_IF; + (*p.tf).esp = PGSIZE; + (*p.tf).eip = 0; // beginning of initcode.S + + // Set process name + let name = b"initcode"; + for (i, &byte) in name.iter().enumerate() { + p.name[i] = byte; + } + + // Set current working directory to root + p.cwd = crate::fs::namei("/").expect("Failed to find root directory"); + + p.state = ProcState::Runnable; + } +} + +// Process scheduler. +// Scheduler never returns. It loops, doing: +// - choose a process to run +// - swtch to start running that process +pub fn scheduler() -> ! { + let c = mycpu(); + c.proc = null_mut(); + + loop { + // Enable interrupts on this processor. + crate::x86::sti(); + + // Loop over process table looking for process to run. + unsafe { + let ptable_ptr = core::ptr::addr_of_mut!(PTABLE); + let ptable = (*ptable_ptr).get_mut().expect("Process table not initialized"); + + for p in &mut ptable.proc { + if p.state != ProcState::Runnable { + continue; + } + + // Switch to chosen process. + c.proc = p as *mut Proc; + p.state = ProcState::Running; + + swtch(p.context); + + // Process is done running for now. + c.proc = null_mut(); + } + } + } } \ No newline at end of file diff --git a/src/spinlock.rs b/src/spinlock.rs new file mode 100644 index 0000000..2e7b2f2 --- /dev/null +++ b/src/spinlock.rs @@ -0,0 +1,32 @@ +// Mutual exclusion spin locks and debugging utilities + +/// Record the current call stack in pcs[] by following the %ebp chain. +/// This function walks the stack frame pointers to collect return addresses. +pub fn getcallerpcs(v: *const u32, pcs: &mut [u32; 10]) { + unsafe { + let mut ebp = v.offset(-2) as *const u32; + let mut i = 0; + + while i < 10 { + // Check for invalid ebp values + // if(ebp == 0 || ebp < (uint*)KERNBASE || ebp == (uint*)0xffffffff) + if ebp.is_null() || ebp == 0xffffffff as *const u32 { + break; + } + + // pcs[i] = ebp[1]; // saved %eip + pcs[i] = *ebp.offset(1); + + // ebp = (uint*)ebp[0]; // saved %ebp + ebp = *ebp as *const u32; + + i += 1; + } + + // Fill rest with zeros + while i < 10 { + pcs[i] = 0; + i += 1; + } + } +} diff --git a/src/vm.rs b/src/vm.rs index 20baffb..7d6984f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,4 +1,4 @@ -use crate::constants::{SEG_KCODE, SEG_KDATA, SEG_UCODE, SEG_UDATA, STA_X, STA_W, STA_R, STARTPROC, PROCSIZE}; +use crate::constants::{SEG_KCODE, SEG_KDATA, SEG_UCODE, SEG_UDATA, STA_X, STA_W, STA_R, STARTPROC, PROCSIZE, DPL_USER}; use crate::mmu::SegDesc; use crate::proc::cpuid; use crate::mp::MP_ONCE; @@ -16,8 +16,8 @@ pub fn seginit() { c.gdt[SEG_KCODE as usize] = SegDesc::seg(STA_X | STA_R, 0, 0xffffffff, 0); c.gdt[SEG_KDATA as usize] = SegDesc::seg(STA_W, 0, 0xffffffff, 0); - c.gdt[SEG_UCODE as usize] = SegDesc::seg(STA_X | STA_R, STARTPROC, PROCSIZE, 0); - c.gdt[SEG_UDATA as usize] = SegDesc::seg(STA_W, STARTPROC, PROCSIZE, 0); + c.gdt[SEG_UCODE as usize] = SegDesc::seg(STA_X | STA_R, STARTPROC, PROCSIZE << 12, DPL_USER); + c.gdt[SEG_UDATA as usize] = SegDesc::seg(STA_W, STARTPROC, PROCSIZE << 12, DPL_USER); lgdt(&c.gdt, size_of_val(&c.gdt)); } } diff --git a/src/x86.rs b/src/x86.rs index 248683d..48187b0 100644 --- a/src/x86.rs +++ b/src/x86.rs @@ -139,6 +139,42 @@ pub fn rcr2() -> u32 { } } +pub fn stosb(addr: *mut u8, data: u8, cnt: usize) { + unsafe { + asm!( + "cld", + "rep stosb", + inout("edi") addr => _, + inout("ecx") cnt => _, + in("al") data, + options(nostack) + ); + } +} + +pub fn stosl(addr: *mut u32, data: u32, cnt: usize) { + unsafe { + asm!( + "cld", + "rep stosl", + inout("edi") addr => _, + inout("ecx") cnt => _, + in("eax") data, + options(nostack) + ); + } +} + +pub fn loadgs(v: u16) { + unsafe { + asm!( + "mov gs, {0:x}", + in(reg) v, + options(nomem, nostack) + ); + } +} + #[repr(C)] pub struct TrapFrame { // registers as pushed by pusha @@ -151,6 +187,15 @@ pub struct TrapFrame { pub ecx: u32, pub eax: u32, + // segment registers + pub gs: u16, + pub padding1: u16, + pub fs: u16, + pub padding2: u16, + pub es: u16, + pub padding3: u16, + pub ds: u16, + pub padding4: u16, pub trapno: u32, // below here defined by x86 hardware @@ -164,4 +209,37 @@ pub struct TrapFrame { pub esp: u32, pub ss: u16, pub padding6: u16, +} + +// Page table/directory helper functions +use crate::constants::{PDXSHIFT, PTXSHIFT}; + +// Extract page directory index from virtual address +#[inline] +pub fn pdx(va: u32) -> usize { + ((va >> PDXSHIFT) & 0x3FF) as usize +} + +// Extract page table index from virtual address +#[inline] +pub fn ptx(va: u32) -> usize { + ((va >> PTXSHIFT) & 0x3FF) as usize +} + +// Construct virtual address from page directory index, page table index, and offset +#[inline] +pub fn pgaddr(d: u32, t: u32, o: u32) -> u32 { + (d << PDXSHIFT) | (t << PTXSHIFT) | o +} + +// Extract address from page table entry +#[inline] +pub fn pte_addr(pte: u32) -> u32 { + pte & !0xFFF +} + +// Extract flags from page table entry +#[inline] +pub fn pte_flags(pte: u32) -> u32 { + pte & 0xFFF } \ No newline at end of file diff --git a/swtch.S b/swtch.S new file mode 100644 index 0000000..60479ec --- /dev/null +++ b/swtch.S @@ -0,0 +1,22 @@ +# Context switch +# +# void swtch(struct context *new); +# +# Save the current registers on the stack, creating +# a struct context, and save its address in *old. +# Switch stacks to new and pop previously-saved registers. + +.globl swtch +swtch: + movl 4(%esp), %eax + + # Switch stacks + movl %eax, %esp + movl $0, %eax + + # Load new callee-saved registers + popl %edi + popl %esi + popl %ebx + popl %ebp + ret diff --git a/trapasm.S b/trapasm.S index 477a5ee..7f46ce1 100644 --- a/trapasm.S +++ b/trapasm.S @@ -4,8 +4,17 @@ .globl alltraps alltraps: # Build trap frame. + pushl %ds + pushl %es + pushl %fs + pushl %gs pushal + # Set up data segments. + movw $(SEG_KDATA<<3), %ax + movw %ax, %ds + movw %ax, %es + # Call trap(tf), where tf=%esp pushl %esp call trap @@ -15,6 +24,10 @@ alltraps: .globl trapret trapret: popal + popl %gs + popl %fs + popl %es + popl %ds addl $0x8, %esp # trapno and errcode iret From 50ea83dfbad5cb4916fa5e2eb09363ea2c84d1d3 Mon Sep 17 00:00:00 2001 From: Yash-Rawat-IIT-D Date: Sat, 14 Mar 2026 18:33:04 +0000 Subject: [PATCH 2/3] Corrected proc.rs as per p19 debuggging --- src/proc.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/proc.rs b/src/proc.rs index 460baed..6356871 100644 --- a/src/proc.rs +++ b/src/proc.rs @@ -4,7 +4,7 @@ use crate::mmu::SegDesc; use crate::x86::TrapFrame; use crate::param::NPROC; use core::ptr::null_mut; -use core::cell::OnceCell; +// use core::cell::OnceCell; // Saved registers for kernel context switches. // Don't need to save all the segment registers (%cs, etc), @@ -68,7 +68,10 @@ struct PTable { proc: [Proc; NPROC], } -static mut PTABLE: OnceCell = OnceCell::new(); +static mut PTABLE: PTable = PTable { + proc: [Proc::new(); NPROC], +}; + static mut NEXTPID: i32 = 1; #[derive(Debug, Clone, Copy)] @@ -122,17 +125,12 @@ extern "C" { // Otherwise return None. fn allocproc() -> Option<&'static mut Proc> { unsafe { - let ptable_ptr = core::ptr::addr_of_mut!(PTABLE); - if (*ptable_ptr).get().is_none() { - let _ = (*ptable_ptr).set(PTable { - proc: [Proc::new(); NPROC], - }); - } + - let ptable = (*ptable_ptr).get_mut().unwrap(); + let ptable = &raw mut PTABLE; - for p in &mut ptable.proc { + for p in &mut (*ptable).proc { if p.state == ProcState::Unused { // Found an unused process p.state = ProcState::Embryo; @@ -216,10 +214,10 @@ pub fn scheduler() -> ! { // Loop over process table looking for process to run. unsafe { - let ptable_ptr = core::ptr::addr_of_mut!(PTABLE); - let ptable = (*ptable_ptr).get_mut().expect("Process table not initialized"); + + let ptable = &raw mut PTABLE; - for p in &mut ptable.proc { + for p in &mut (*ptable).proc { if p.state != ProcState::Runnable { continue; } From 7c0ffc295bad3642e29fbcbec675d7a47f1e1739 Mon Sep 17 00:00:00 2001 From: KoRaghav Date: Fri, 8 May 2026 13:43:05 +0530 Subject: [PATCH 3/3] cleanup --- src/main.rs | 2 ++ src/mmu.rs | 32 +++++++++++++++++++++++++++++++- src/proc.rs | 19 ++++++++----------- src/vm.rs | 3 +++ src/x86.rs | 33 --------------------------------- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7e9540d..0853b3d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,11 +83,13 @@ pub extern "C" fn entryofrust() -> ! { x86::sti(); fs::iinit(param::ROOTDEV); log::initlog(param::ROOTDEV); + // cli(); // disable interrupts file::mknod("/console", param::CONSOLE as i16, param::CONSOLE as i16); vm::seginit(); // segment descriptors proc::pinit(); // first process proc::scheduler(); // start running processes (never returns) } + static mut PANICKED: bool = false; #[cfg(not(test))] diff --git a/src/mmu.rs b/src/mmu.rs index 505b33a..7e5d378 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,9 +1,9 @@ #![allow(unused_parens)] // False positive from bitfield macro use modular_bitfield::prelude::*; +use crate::constants::{PDXSHIFT, PTXSHIFT}; // Page table/directory helper functions // Segment Descriptor - #[bitfield] #[repr(C, packed)] #[derive(Clone, Copy, Default, Debug)] @@ -44,3 +44,33 @@ impl SegDesc { seg } } + +// Extract page directory index from virtual address +#[inline] +pub fn pdx(va: u32) -> usize { + ((va >> PDXSHIFT) & 0x3FF) as usize +} + +// Extract page table index from virtual address +#[inline] +pub fn ptx(va: u32) -> usize { + ((va >> PTXSHIFT) & 0x3FF) as usize +} + +// Construct virtual address from page directory index, page table index, and offset +#[inline] +pub fn pgaddr(d: u32, t: u32, o: u32) -> u32 { + (d << PDXSHIFT) | (t << PTXSHIFT) | o +} + +// Extract address from page table entry +#[inline] +pub fn pte_addr(pte: u32) -> u32 { + pte & !0xFFF +} + +// Extract flags from page table entry +#[inline] +pub fn pte_flags(pte: u32) -> u32 { + pte & 0xFFF +} \ No newline at end of file diff --git a/src/proc.rs b/src/proc.rs index 6356871..014ad47 100644 --- a/src/proc.rs +++ b/src/proc.rs @@ -1,7 +1,9 @@ use crate::mp::MP_ONCE; use crate::constants::{NSEGS, SEG_UCODE, SEG_UDATA, DPL_USER, FL_IF, PGSIZE, STARTPROC, PROCSIZE}; +use crate::fs::namei; use crate::mmu::SegDesc; -use crate::x86::TrapFrame; +use crate::println; +use crate::x86::{TrapFrame, sti}; use crate::param::NPROC; use core::ptr::null_mut; // use core::cell::OnceCell; @@ -125,9 +127,6 @@ extern "C" { // Otherwise return None. fn allocproc() -> Option<&'static mut Proc> { unsafe { - - - let ptable = &raw mut PTABLE; for p in &mut (*ptable).proc { @@ -192,9 +191,8 @@ pub fn pinit() { for (i, &byte) in name.iter().enumerate() { p.name[i] = byte; } - // Set current working directory to root - p.cwd = crate::fs::namei("/").expect("Failed to find root directory"); + p.cwd = namei("/").expect("Failed to find root directory"); p.state = ProcState::Runnable; } @@ -210,18 +208,17 @@ pub fn scheduler() -> ! { loop { // Enable interrupts on this processor. - crate::x86::sti(); + sti(); // Loop over process table looking for process to run. unsafe { - - let ptable = &raw mut PTABLE; - + + let ptable = &raw mut PTABLE; for p in &mut (*ptable).proc { if p.state != ProcState::Runnable { continue; } - + // Switch to chosen process. c.proc = p as *mut Proc; p.state = ProcState::Running; diff --git a/src/vm.rs b/src/vm.rs index 7d6984f..598f42f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -10,6 +10,9 @@ use core::mem::size_of_val; pub fn seginit() { unsafe { // Map "logical" addresses to virtual addresses using identity map. + // Cannot share a CODE descriptor for both kernel and user + // because it would have to have DPL_USR, but the CPU forbids + // an interrupt from CPL=0 to DPL=3. let cpus = MP_ONCE.cpus.get().expect("CPUs not initialized"); let cpu_ptr = cpus.as_ptr() as *mut crate::proc::Cpu; let c = &mut *cpu_ptr.add(cpuid()); diff --git a/src/x86.rs b/src/x86.rs index 48187b0..48f24df 100644 --- a/src/x86.rs +++ b/src/x86.rs @@ -210,36 +210,3 @@ pub struct TrapFrame { pub ss: u16, pub padding6: u16, } - -// Page table/directory helper functions -use crate::constants::{PDXSHIFT, PTXSHIFT}; - -// Extract page directory index from virtual address -#[inline] -pub fn pdx(va: u32) -> usize { - ((va >> PDXSHIFT) & 0x3FF) as usize -} - -// Extract page table index from virtual address -#[inline] -pub fn ptx(va: u32) -> usize { - ((va >> PTXSHIFT) & 0x3FF) as usize -} - -// Construct virtual address from page directory index, page table index, and offset -#[inline] -pub fn pgaddr(d: u32, t: u32, o: u32) -> u32 { - (d << PDXSHIFT) | (t << PTXSHIFT) | o -} - -// Extract address from page table entry -#[inline] -pub fn pte_addr(pte: u32) -> u32 { - pte & !0xFFF -} - -// Extract flags from page table entry -#[inline] -pub fn pte_flags(pte: u32) -> u32 { - pte & 0xFFF -} \ No newline at end of file