Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ pub const SEG_UCODE: u16 = 3; // user code
pub const SEG_UDATA: u16 = 4; // user data+stack
pub const SEG_TSS: u16 = 5; // this process's task state

// cpu->gdt[NSEGS] holds the above segments.
pub const NSEGS: usize = 6;

// 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
// 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)

// System segment type bits
pub const STS_T32A: u8 = 0x9; // Available 32-bit TSS
pub const STS_IG32: u8 = 0xE; // 32-bit Interrupt Gate
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ mod fs;
mod fcntl;
mod file;
mod log;
mod mmu;
mod vm;
use crate::traps::*;

fn halt() -> ! {
Expand Down Expand Up @@ -81,6 +83,7 @@ pub extern "C" fn entryofrust() -> ! {
fs::iinit(param::ROOTDEV);
log::initlog(param::ROOTDEV);
file::mknod("/console", param::CONSOLE as i16, param::CONSOLE as i16);
vm::seginit(); // segment descriptors
welcome();

loop {
Expand Down
46 changes: 46 additions & 0 deletions src/mmu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#![allow(unused_parens)] // False positive from bitfield macro

use modular_bitfield::prelude::*;

// Segment Descriptor

#[bitfield]
#[repr(C, packed)]
#[derive(Clone, Copy, Default, Debug)]
pub struct SegDesc {
lim_15_0: B16, // Low bits of segment limit
base_15_0: B16, // Low bits of segment base address
base_23_16: B8, // Middle bits of segment base address
seg_type: B4, // Segment type (see STA_ constants)
s: B1, // 0 = system, 1 = application
dpl: B2, // Descriptor Privilege Level
p: B1, // Present
lim_19_16: B4, // High bits of segment limit
avl: B1, // Unused (available for software use)
rsv1: B1, // Reserved
db: B1, // 0 = 16-bit segment, 1 = 32-bit segment
g: B1, // Granularity: limit scaled by 4K when set
base_31_24: B8, // High bits of segment base address
}

impl SegDesc {
/// Create a normal segment descriptor
/// Matches the C macro: SEG(type, base, lim, dpl)
pub fn seg(seg_type: u8, base: u32, lim: u32, dpl: u8) -> Self {
let mut seg = SegDesc::default();
seg.set_lim_15_0(((lim >> 12) & 0xffff) as u16);
seg.set_base_15_0((base & 0xffff) as u16);
seg.set_base_23_16(((base >> 16) & 0xff) as u8);
seg.set_seg_type(seg_type);
seg.set_s(1);
seg.set_dpl(dpl);
seg.set_p(1);
seg.set_lim_19_16((lim >> 28) as u8);
seg.set_avl(0);
seg.set_rsv1(0);
seg.set_db(1);
seg.set_g(1);
seg.set_base_31_24(((base >> 24) & 0xff) as u8);
seg
}
}
31 changes: 8 additions & 23 deletions src/proc.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use crate::mp::MP_ONCE; // Import the MP_ONCE static from mp.rs
// use core::ptr;
use crate::x86::readeflags;
use crate::param::{NCPU};
use crate::constants::{FL_IF};
use crate::lapic;
use crate::constants::NSEGS;
use crate::mmu::SegDesc;

#[derive(Debug, Clone, Copy)]
pub struct Cpu {
pub apicid: u8, // Local APIC ID
pub gdt: [SegDesc; NSEGS], // x86 global descriptor table
}

impl Cpu {
pub const fn new() -> Self {
Self { apicid: 0 }
Self {
apicid: 0,
gdt: [SegDesc::new(); NSEGS],
}
}
}

Expand All @@ -22,23 +24,6 @@ pub fn cpuid() -> usize {
}

pub fn mycpu() -> &'static Cpu {
let apicid: usize;
let mut i: usize = 0;

if readeflags() & FL_IF != 0 {
panic!("mycpu called with interrupts enabled\n");
}

apicid = lapic::lapicid() as usize;

// Access the cpus array via MP_ONCE
let cpus = MP_ONCE.cpus.get().expect("CPUs not initialized");

while i < NCPU {
if (cpus[i].apicid as usize) == apicid {
return &cpus[i];
}
i += 1;
}
panic!("unknown apicid\n");
&cpus[0]
}
23 changes: 23 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::constants::{SEG_KCODE, SEG_KDATA, SEG_UCODE, SEG_UDATA, STA_X, STA_W, STA_R, STARTPROC, PROCSIZE};
use crate::mmu::SegDesc;
use crate::proc::cpuid;
use crate::mp::MP_ONCE;
use crate::x86::lgdt;
use core::mem::size_of_val;

/// Set up CPU's kernel segment descriptors.
/// Run once on entry on each CPU.
pub fn seginit() {
unsafe {
// Map "logical" addresses to virtual addresses using identity map.
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());

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);
lgdt(&c.gdt, size_of_val(&c.gdt));
}
}
28 changes: 17 additions & 11 deletions src/x86.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::arch::asm;
use crate::traps::GateDesc;
use crate::mmu::SegDesc;
use crate::constants::NSEGS;

pub fn inb(port: u16) -> u8 {
let result: u8;
Expand Down Expand Up @@ -36,17 +38,6 @@ pub fn outw(port: u16, value: u16) {
}
}

pub fn readeflags() -> u32 {
unsafe {
let eflags: u32;
asm!(
"pushfd; pop eax",
out("eax") eflags,
options(nomem, nostack)
);
eflags
}
}

pub fn cli () {
unsafe {
Expand Down Expand Up @@ -75,6 +66,21 @@ pub fn lidt(gdt: *const [GateDesc; 256], size: usize) {
}
}

pub fn lgdt(gdt: *const [SegDesc; NSEGS], size: usize) {
let pd: [u16; 3] = [
(size - 1) as u16,
(gdt as *const _) as u16,
((gdt as *const _ as u32) >> 16) as u16,
];
unsafe {
asm!(
"lgdt [{0:e}]",
in(reg) (&pd as *const _ ) as u32,
options(nostack, readonly)
);
}
}

pub fn noop() {
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
Expand Down