aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ATTRIBUTIONS44
-rw-r--r--src/arch/x86_64/mod.rs1
-rw-r--r--src/arch/x86_64/paging/mod.rs220
-rw-r--r--src/lib.rs1
4 files changed, 252 insertions, 14 deletions
diff --git a/ATTRIBUTIONS b/ATTRIBUTIONS
index b59a123..bd8a666 100644
--- a/ATTRIBUTIONS
+++ b/ATTRIBUTIONS
@@ -13,43 +13,59 @@ Author(s):
Tianhao Wang <shrik3@mailbox.org>
+---------------------------------------------------------+
-| derived works from rust-osdev/bootloader |
+| derived works from intermezzOS |
+---------------------------------------------------------+
copyright:
- 2018 Philipp Oppermann
+ Copyright (c) 2016 intermezzOS Developers
license:
- MIT License
- https://github.com/rust-osdev/bootloader/blob/main/LICENSE-MIT
+ MIT license
+ https://github.com/intermezzOS/kernel/blob/master/LICENSE-MIT
files:
- boot/mod.rs
+ boot/startup-x86_64.s
+ defs/x86_64-linker.ld
source:
- https://github.com/rust-osdev/bootloader/tree/main
+ https://github.com/intermezzOS/kernel
+
+---------------------------------------------------------+
-| derived works from intermezzOS |
+| derived works from x86_64 (rust crate) |
+---------------------------------------------------------+
copyright:
- Copyright (c) 2016 intermezzOS Developers
+ Copyright (c) 2018 Philipp Oppermann
+ Copyright (c) 2015 Gerd Zellweger
+ Copyright (c) 2015 The libcpu Developers
license:
- MIT license
- https://github.com/intermezzOS/kernel/blob/master/LICENSE-MIT
+ MIT license
+ https://docs.rs/crate/x86_64/latest/source/LICENSE-MIT
files:
- boot/startup-x86_64.s
- defs/x86_64-linker.ld
+ src/arch/x86_64/paging
source:
- https://github.com/intermezzOS/kernel
+ https://docs.rs/x86_64/latest/src/x86_64/structures/paging/page_table.rs
-----------------------------------------------------------
+---------------------------------------------------------+
-| attributions for inspirations |
+| rust-osdev/bootloader (inspiration) |
++---------------------------------------------------------+
+copyright:
+ 2018 Philipp Oppermann
+
+license:
+ MIT License
+ https://github.com/rust-osdev/bootloader/blob/main/LICENSE-MIT
+
+source:
+ https://github.com/rust-osdev/bootloader/tree/main
+
++---------------------------------------------------------+
+| the original OOStuBS (inspiration) |
+---------------------------------------------------------+
OOStuBS
Institut für Verteilte Systeme (IVS),
diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs
index 4da1970..888cafd 100644
--- a/src/arch/x86_64/mod.rs
+++ b/src/arch/x86_64/mod.rs
@@ -3,3 +3,4 @@ pub mod interrupt;
pub mod io_port;
pub mod mem;
pub mod misc;
+pub mod paging;
diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs
new file mode 100644
index 0000000..ab93938
--- /dev/null
+++ b/src/arch/x86_64/paging/mod.rs
@@ -0,0 +1,220 @@
+// code derived from the x86_64 crate
+// https://docs.rs/x86_64/latest/src/x86_64/addr.rs.html
+// see ATTRIBUTIONS
+use crate::defs::*;
+use bitflags::bitflags;
+#[repr(align(4096))]
+#[repr(C)]
+#[derive(Clone)]
+pub struct Pagetable {
+ entries: [PTE; Self::ENTRY_COUNT],
+}
+
+#[derive(Clone)]
+#[repr(transparent)]
+pub struct PTE {
+ entry: u64,
+}
+
+// use wrapped VA and PA instead of simply u64 as a sanity check:
+// VA must be sign extended, PA has at most 52 bits
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[repr(transparent)]
+pub struct VAddr(u64);
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[repr(transparent)]
+pub struct PAddr(u64);
+
+bitflags! {
+pub struct PTEFlags:u64 {
+ const ZERO = 0;
+ const PRESENT = 1 << 0;
+ const WRITABLE = 1 << 1;
+ const USER = 1 << 2;
+ const WT = 1 << 3;
+ const NC = 1 << 4;
+ const ACCESSED = 1 << 5;
+ const DIRTY = 1 << 6;
+ const HUGE_PAGE = 1 << 7;
+ const GLOBAL = 1 << 8;
+ const B9 = 1 << 9;
+ const B10 = 1 << 10;
+ const B11 = 1 << 11;
+ // [51:12] is used for translation address
+ // [62:52] are user defined.
+ // [63] NO_EXECUTE, needs to be enabled in EFER.
+ const NE = 1 << 63;
+}
+}
+
+impl Pagetable {
+ const ENTRY_COUNT: usize = 512;
+ /// Creates an empty page table.
+ #[inline]
+ pub const fn new() -> Self {
+ const EMPTY: PTE = PTE::new();
+ Pagetable {
+ entries: [EMPTY; Self::ENTRY_COUNT],
+ }
+ }
+
+ /// Clears all entries.
+ #[inline]
+ pub fn zero(&mut self) {
+ for entry in self.iter_mut() {
+ entry.set_unused();
+ }
+ }
+
+ /// Returns an iterator over the entries of the page table.
+ #[inline]
+ pub fn iter(&self) -> impl Iterator<Item = &PTE> {
+ (0..512).map(move |i| &self.entries[i])
+ }
+
+ /// Returns an iterator that allows modifying the entries of the page table.
+ #[inline]
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PTE> {
+ // Note that we intentionally don't just return `self.entries.iter()`:
+ // Some users may choose to create a reference to a page table at
+ // `0xffff_ffff_ffff_f000`. This causes problems because calculating
+ // the end pointer of the page tables causes an overflow. Therefore
+ // creating page tables at that address is unsound and must be avoided.
+ // Unfortunately creating such page tables is quite common when
+ // recursive page tables are used, so we try to avoid calculating the
+ // end pointer if possible. `core::slice::Iter` calculates the end
+ // pointer to determine when it should stop yielding elements. Because
+ // we want to avoid calculating the end pointer, we don't use
+ // `core::slice::Iter`, we implement our own iterator that doesn't
+ // calculate the end pointer. This doesn't make creating page tables at
+ // that address sound, but it avoids some easy to trigger
+ // miscompilations.
+ let ptr = self.entries.as_mut_ptr();
+ (0..512).map(move |i| unsafe { &mut *ptr.add(i) })
+ }
+
+ /// Checks if the page table is empty (all entries are zero).
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.iter().all(|entry| entry.is_unused())
+ }
+}
+
+impl VAddr {
+ #[inline]
+ pub const fn new(addr: u64) -> VAddr {
+ return Self::try_new(addr).expect("VA must be sign extended in 16 MSBs");
+ }
+
+ #[inline]
+ pub const fn try_new(addr: u64) -> Option<VAddr> {
+ let v = Self::new_truncate(addr);
+ if v.0 == addr {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub const fn new_truncate(addr: u64) -> VAddr {
+ // sign extend the upper bits
+ VAddr(((addr << 16) as i64 >> 16) as u64)
+ }
+
+ #[inline]
+ pub const fn as_u64(self) -> u64 {
+ self.0
+ }
+
+ /// Converts the address to a raw pointer.
+ #[cfg(target_pointer_width = "64")]
+ #[inline]
+ pub const fn as_ptr<T>(self) -> *const T {
+ self.as_u64() as *const T
+ }
+
+ /// Converts the address to a mutable raw pointer.
+ #[cfg(target_pointer_width = "64")]
+ #[inline]
+ pub const fn as_mut_ptr<T>(self) -> *mut T {
+ self.as_ptr::<T>() as *mut T
+ }
+
+ /// Returns the 9-bit level 1 page table index.
+ #[inline]
+ pub const fn p1_index(self) -> usize {
+ (self.0 >> 12) as usize
+ }
+
+ /// Returns the 9-bit level 2 page table index.
+ #[inline]
+ pub const fn p2_index(self) -> usize {
+ (self.0 >> 12 >> 9) as usize
+ }
+
+ /// Returns the 9-bit level 3 page table index.
+ #[inline]
+ pub const fn p3_index(self) -> usize {
+ (self.0 >> 12 >> 9 >> 9) as usize
+ }
+
+ /// Returns the 9-bit level 4 page table index.
+ #[inline]
+ pub const fn p4_index(self) -> usize {
+ (self.0 >> 12 >> 9 >> 9 >> 9) as usize
+ }
+}
+
+impl PAddr {
+ #[inline]
+ pub const fn new(addr: u64) -> Self {
+ Self::try_new(addr).expect("PA shall not have more than 52 bits")
+ }
+
+ /// Creates a new physical address, throwing bits 52..64 away.
+ #[inline]
+ pub const fn new_truncate(addr: u64) -> PAddr {
+ PAddr(addr % (1 << 52))
+ }
+
+ /// Tries to create a new physical address.
+ /// Fails if any bits in the range 52 to 64 are set.
+ #[inline]
+ pub const fn try_new(addr: u64) -> Option<Self> {
+ let p = Self::new_truncate(addr);
+ if p.0 == addr {
+ Some(p)
+ } else {
+ None
+ }
+ }
+}
+
+impl PTE {
+ #[inline]
+ pub const fn new() -> Self {
+ PTE { entry: 0 }
+ }
+
+ #[inline]
+ pub const fn is_unused(&self) -> bool {
+ self.entry == 0
+ }
+
+ #[inline]
+ pub fn set_unused(&mut self) -> bool {
+ self.entry == 0
+ }
+
+ #[inline]
+ pub const fn flags(&self) -> PTEFlags {
+ // from_bits_truncate ignores undefined bits.
+ PTEFlags::from_bits_truncate(self.entry)
+ }
+
+ #[inline]
+ pub const fn addr(&self) -> PAddr {
+ PAddr::new(self.entry & 0x000f_ffff_ffff_f000)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 0eb1c7d..8b561ce 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,7 @@
#![allow(unused_imports)]
#![no_std]
#![no_main]
+#![feature(const_option)]
mod arch;
mod defs;
mod ds;