Initial commit
This commit is contained in:
commit
d602398062
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
40
Cargo.lock
generated
Normal file
40
Cargo.lock
generated
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "address"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-a"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "509fc35485a2b4ddbacabe0bf2212cdfff88da93658608e5cc651afcb75b7733"
|
||||||
|
dependencies = [
|
||||||
|
"tock-registers",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "error"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-a",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osdev5"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tock-registers"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "osdev5"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"kernel",
|
||||||
|
"address",
|
||||||
|
"error"
|
||||||
|
]
|
9
address/Cargo.toml
Normal file
9
address/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "address"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
error = { path = "../error" }
|
0
address/src/base/mod.rs
Normal file
0
address/src/base/mod.rs
Normal file
21
address/src/lib.rs
Normal file
21
address/src/lib.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//! Type-safe wrappers for different address kinds
|
||||||
|
#![no_std]
|
||||||
|
#![feature(
|
||||||
|
step_trait,
|
||||||
|
const_fn_trait_bound,
|
||||||
|
const_trait_impl,
|
||||||
|
const_panic
|
||||||
|
)]
|
||||||
|
// #![warn(missing_docs)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
pub mod virt;
|
||||||
|
pub mod phys;
|
||||||
|
|
||||||
|
trait Address {}
|
||||||
|
|
||||||
|
pub use phys::PhysicalAddress;
|
||||||
|
pub use virt::{AddressSpace, NoTrivialConvert, TrivialConvert, VirtualAddress};
|
177
address/src/phys.rs
Normal file
177
address/src/phys.rs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
use crate::{AddressSpace, TrivialConvert, VirtualAddress};
|
||||||
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt;
|
||||||
|
use core::iter::Step;
|
||||||
|
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(PartialEq, PartialOrd, Copy, Clone)]
|
||||||
|
pub struct PhysicalAddress(usize);
|
||||||
|
|
||||||
|
// Arithmetic
|
||||||
|
impl<A: Into<usize>> Add<A> for PhysicalAddress {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn add(self, rhs: A) -> Self {
|
||||||
|
// Will panic on overflow
|
||||||
|
Self::from(self.0 + rhs.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A: Into<usize>> AddAssign<A> for PhysicalAddress {
|
||||||
|
#[inline(always)]
|
||||||
|
fn add_assign(&mut self, rhs: A) {
|
||||||
|
// Will panic on overflow
|
||||||
|
*self = Self::from(self.0 + rhs.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Sub<usize> for PhysicalAddress {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub(self, rhs: usize) -> Self {
|
||||||
|
Self::from(self.0 - rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl SubAssign<usize> for PhysicalAddress {
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub_assign(&mut self, rhs: usize) {
|
||||||
|
*self = Self::from(self.0 - rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construction
|
||||||
|
impl From<usize> for PhysicalAddress {
|
||||||
|
fn from(p: usize) -> Self {
|
||||||
|
Self(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
impl From<u64> for PhysicalAddress {
|
||||||
|
fn from(p: u64) -> Self {
|
||||||
|
Self(p as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhysicalAddress {
|
||||||
|
pub const fn new(value: usize) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn add(self, value: usize) -> Self {
|
||||||
|
Self(self.0 + value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn diff(start: PhysicalAddress, end: PhysicalAddress) -> isize {
|
||||||
|
if end >= start {
|
||||||
|
isize::try_from(end.0 - start.0).expect("Address subtraction overflowed")
|
||||||
|
} else {
|
||||||
|
-isize::try_from(start.0 - end.0).expect("Address subtraction overflowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn diff_unchecked(start: PhysicalAddress, end: PhysicalAddress) -> isize {
|
||||||
|
end.0 as isize - start.0 as isize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn is_paligned(self) -> bool {
|
||||||
|
return self.0 & 0xFFF == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn page_index(self) -> usize {
|
||||||
|
self.0 >> 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trivial conversion PhysicalAddress -> VirtualAddress
|
||||||
|
impl<T: AddressSpace + TrivialConvert> const From<PhysicalAddress> for VirtualAddress<T> {
|
||||||
|
fn from(p: PhysicalAddress) -> Self {
|
||||||
|
VirtualAddress::from(p.0 + T::OFFSET)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const From<PhysicalAddress> for usize {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: PhysicalAddress) -> Self {
|
||||||
|
p.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
impl From<PhysicalAddress> for u64 {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: PhysicalAddress) -> Self {
|
||||||
|
p.0 as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatting
|
||||||
|
impl fmt::Debug for PhysicalAddress {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "<phys {:#018x}>", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step
|
||||||
|
impl Step for PhysicalAddress {
|
||||||
|
#[inline]
|
||||||
|
fn steps_between(_p0: &Self, _p1: &Self) -> Option<usize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn forward_checked(p: Self, steps: usize) -> Option<Self> {
|
||||||
|
p.0.checked_add(steps).map(Self::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backward_checked(p: Self, steps: usize) -> Option<Self> {
|
||||||
|
p.0.checked_sub(steps).map(Self::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{AddressSpace, NoTrivialConvert, TrivialConvert, VirtualAddress};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
||||||
|
struct S0;
|
||||||
|
impl AddressSpace for S0 {
|
||||||
|
const NAME: &'static str = "S0";
|
||||||
|
const OFFSET: usize = 0x8000;
|
||||||
|
const LIMIT: usize = Self::OFFSET + 0x4000;
|
||||||
|
}
|
||||||
|
impl TrivialConvert for S0 {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
||||||
|
struct S1;
|
||||||
|
impl AddressSpace for S1 {
|
||||||
|
const NAME: &'static str = "S1";
|
||||||
|
const OFFSET: usize = 0;
|
||||||
|
const LIMIT: usize = 0;
|
||||||
|
}
|
||||||
|
impl NoTrivialConvert for S1 {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_virt_convert_valid() {
|
||||||
|
let p0 = PhysicalAddress::from(0x1234usize);
|
||||||
|
assert_eq!(
|
||||||
|
VirtualAddress::<S0>::from(p0),
|
||||||
|
VirtualAddress::<S0>::from(0x9234usize)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_virt_convert_invalid() {
|
||||||
|
let p0 = PhysicalAddress::from(0x4321usize);
|
||||||
|
let _v = VirtualAddress::<S0>::from(p0);
|
||||||
|
}
|
||||||
|
}
|
364
address/src/virt.rs
Normal file
364
address/src/virt.rs
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
use super::PhysicalAddress;
|
||||||
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt;
|
||||||
|
use core::iter::Step;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
|
pub trait AddressSpace: Copy + Clone + PartialEq + PartialOrd {
|
||||||
|
const NAME: &'static str;
|
||||||
|
const OFFSET: usize;
|
||||||
|
const LIMIT: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NoTrivialConvert {}
|
||||||
|
pub trait TrivialConvert {}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone, PartialOrd, PartialEq)]
|
||||||
|
pub struct VirtualAddress<Kind: AddressSpace>(usize, PhantomData<Kind>);
|
||||||
|
|
||||||
|
// Arithmetic
|
||||||
|
impl<T: AddressSpace> Add<usize> for VirtualAddress<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn add(self, rhs: usize) -> Self {
|
||||||
|
// Will panic on overflow
|
||||||
|
Self::from(self.0 + rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AddressSpace> AddAssign<usize> for VirtualAddress<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
|
// Will panic on overflow
|
||||||
|
*self = Self::from(self.0 + rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AddressSpace> Sub<usize> for VirtualAddress<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub(self, rhs: usize) -> Self {
|
||||||
|
// Will panic on underflow
|
||||||
|
Self::from(self.0 - rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AddressSpace> SubAssign<usize> for VirtualAddress<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub_assign(&mut self, rhs: usize) {
|
||||||
|
// Will panic on underflow
|
||||||
|
*self = Self::from(self.0 - rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trivial conversion VirtualAddress -> PhysicalAddress
|
||||||
|
impl<T: AddressSpace + TrivialConvert> From<VirtualAddress<T>> for PhysicalAddress {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(virt: VirtualAddress<T>) -> Self {
|
||||||
|
assert!(virt.0 < T::LIMIT);
|
||||||
|
PhysicalAddress::from(virt.0 - T::OFFSET)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatting
|
||||||
|
impl<T: AddressSpace> fmt::Debug for VirtualAddress<T> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "<{} {:#018x}>", T::NAME, self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AddressSpace> VirtualAddress<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn null() -> Self {
|
||||||
|
Self(0, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_subtract(self, p: usize) -> Option<Self> {
|
||||||
|
let (res, overflow) = self.0.overflowing_sub(p);
|
||||||
|
if overflow || res < T::OFFSET || res >= T::LIMIT {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self(res, PhantomData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn diff(start: Self, end: Self) -> isize {
|
||||||
|
if end >= start {
|
||||||
|
isize::try_from(end.0 - start.0).expect("Address subtraction overflowed")
|
||||||
|
} else {
|
||||||
|
-isize::try_from(start.0 - end.0).expect("Address subtraction overflowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn try_diff(start: Self, end: Self) -> Option<isize> {
|
||||||
|
if end >= start {
|
||||||
|
isize::try_from(end.0 - start.0).ok()
|
||||||
|
} else {
|
||||||
|
isize::try_from(start.0 - end.0).map(Neg::neg).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_slice_mut<U>(self, count: usize) -> &'static mut [U] {
|
||||||
|
core::slice::from_raw_parts_mut(self.0 as *mut _, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_mut_ptr<U>(self) -> *mut U {
|
||||||
|
self.0 as *mut U
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_ptr<U>(self) -> *const U {
|
||||||
|
self.0 as *const U
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_mut<U>(self) -> Option<&'static mut U> {
|
||||||
|
(self.0 as *mut U).as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn from_ptr<U>(r: *const U) -> Self {
|
||||||
|
Self::from(r as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn from_ref<U>(r: &U) -> Self {
|
||||||
|
Self(r as *const U as usize, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step
|
||||||
|
impl<T: AddressSpace> Step for VirtualAddress<T> {
|
||||||
|
#[inline]
|
||||||
|
fn steps_between(_p0: &Self, _p1: &Self) -> Option<usize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn forward_checked(p: Self, steps: usize) -> Option<Self> {
|
||||||
|
p.0.checked_add(steps).map(Self::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backward_checked(p: Self, steps: usize) -> Option<Self> {
|
||||||
|
p.0.checked_sub(steps).map(Self::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion into VirtualAddress
|
||||||
|
impl<T: AddressSpace> const From<usize> for VirtualAddress<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: usize) -> Self {
|
||||||
|
if T::LIMIT > 0 {
|
||||||
|
assert!(p >= T::OFFSET && p < T::LIMIT);
|
||||||
|
}
|
||||||
|
Self(p, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
impl<T: AddressSpace> From<u64> for VirtualAddress<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: u64) -> Self {
|
||||||
|
Self::from(p as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion from VirtualAddress
|
||||||
|
impl<T: AddressSpace> From<VirtualAddress<T>> for usize {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: VirtualAddress<T>) -> Self {
|
||||||
|
p.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
impl<T: AddressSpace> From<VirtualAddress<T>> for u64 {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(p: VirtualAddress<T>) -> Self {
|
||||||
|
p.0 as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::PhysicalAddress;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
||||||
|
struct S0;
|
||||||
|
impl AddressSpace for S0 {
|
||||||
|
const NAME: &'static str = "S0";
|
||||||
|
const OFFSET: usize = 0x8000;
|
||||||
|
const LIMIT: usize = Self::OFFSET + 0x4000;
|
||||||
|
}
|
||||||
|
impl TrivialConvert for S0 {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
||||||
|
struct S1;
|
||||||
|
impl AddressSpace for S1 {
|
||||||
|
const NAME: &'static str = "S1";
|
||||||
|
const OFFSET: usize = 0;
|
||||||
|
const LIMIT: usize = 0;
|
||||||
|
}
|
||||||
|
impl NoTrivialConvert for S1 {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trivial_construct_valid() {
|
||||||
|
for i in 0x8000usize..0xC000 {
|
||||||
|
VirtualAddress::<S0>::from(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_trivial_construct_invalid_0() {
|
||||||
|
let _v = VirtualAddress::<S0>::from(0x1234usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_trivial_construct_invalid_1() {
|
||||||
|
let _v = VirtualAddress::<S0>::from(0xD123usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trivial_convert() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8123usize);
|
||||||
|
assert_eq!(
|
||||||
|
PhysicalAddress::from(v0),
|
||||||
|
PhysicalAddress::from(0x123usize)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_valid() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
assert_eq!(VirtualAddress::<S0>::from(0x8223usize), v0 + 0x123usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_add_overflow() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
let _v = v0 - 0xF123usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subtract_valid() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
assert_eq!(VirtualAddress::<S0>::from(0x8023usize), v0 - 0xDDusize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_subtract_overflow() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
let _v = v0 - 0x1234usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_subtract() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
assert_eq!(v0.try_subtract(0x1234usize), None);
|
||||||
|
assert_eq!(
|
||||||
|
v0.try_subtract(0x12usize),
|
||||||
|
Some(VirtualAddress::<S0>::from(0x80EEusize))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_assign_valid() {
|
||||||
|
let mut v0 = VirtualAddress::<S0>::from(0x8100usize);
|
||||||
|
v0 += 0x123usize;
|
||||||
|
assert_eq!(v0, VirtualAddress::<S0>::from(0x8223usize));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sub_assign_valid() {
|
||||||
|
let mut v0 = VirtualAddress::<S0>::from(0x8321usize);
|
||||||
|
v0 -= 0x123usize;
|
||||||
|
assert_eq!(v0, VirtualAddress::<S0>::from(0x81FEusize));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_sub_assign_overflow() {
|
||||||
|
let mut v0 = VirtualAddress::<S0>::from(0x8321usize);
|
||||||
|
v0 -= 0x1234usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_add_assign_overflow() {
|
||||||
|
let mut v0 = VirtualAddress::<S0>::from(0x8321usize);
|
||||||
|
v0 += 0xF234usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8123usize);
|
||||||
|
assert_eq!(&format!("{:?}", v0), "<S0 0x0000000000008123>");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_diff() {
|
||||||
|
let v0 = VirtualAddress::<S0>::from(0x8123usize);
|
||||||
|
let v1 = VirtualAddress::<S0>::from(0x8321usize);
|
||||||
|
|
||||||
|
// Ok
|
||||||
|
assert_eq!(VirtualAddress::diff(v0, v1), 510);
|
||||||
|
assert_eq!(VirtualAddress::diff(v1, v0), -510);
|
||||||
|
assert_eq!(VirtualAddress::diff(v0, v0), 0);
|
||||||
|
assert_eq!(VirtualAddress::diff(v1, v1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_diff_overflow() {
|
||||||
|
let v0 = VirtualAddress::<S1>::from(0usize);
|
||||||
|
let v1 = VirtualAddress::<S1>::from(usize::MAX);
|
||||||
|
|
||||||
|
let _v = VirtualAddress::diff(v0, v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_step() {
|
||||||
|
let mut count = 0;
|
||||||
|
for _ in VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(count, 0x300);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for _ in (VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize))
|
||||||
|
.step_by(0x100)
|
||||||
|
{
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(count, 3);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for _ in
|
||||||
|
(VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize)).rev()
|
||||||
|
{
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(count, 0x300);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for _ in (VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize))
|
||||||
|
.rev()
|
||||||
|
.step_by(0x100)
|
||||||
|
{
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(count, 3);
|
||||||
|
}
|
||||||
|
}
|
35
build.sh
Executable file
35
build.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. etc/common.sh
|
||||||
|
|
||||||
|
CARGO_OPTS="--target ../etc/${ARCH}-${MACH}.json"
|
||||||
|
CARGO_FEATURES=""
|
||||||
|
LLVM_BIN=$(llvm-config --bindir)
|
||||||
|
|
||||||
|
if [ ! "$MACH" = "none" ]; then
|
||||||
|
CARGO_FEATURES="${CARGO_FEATURES}mach_${MACH},"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CARGO_OPTS="$CARGO_OPTS --features=$CARGO_FEATURES"
|
||||||
|
|
||||||
|
if [ "$PROFILE" = "release" ]; then
|
||||||
|
CARGO_OPTS="$CARGO_OPTS --release"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd kernel
|
||||||
|
cargo build ${CARGO_OPTS}
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
case $ARCH in
|
||||||
|
aarch64)
|
||||||
|
${LLVM_BIN}/llvm-objcopy -O binary ${OUT_DIR}/kernel ${OUT_DIR}/kernel.bin
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
mkdir -p ${OUT_DIR}/cdrom/boot/grub
|
||||||
|
cp etc/x86_64-none.grub ${OUT_DIR}/cdrom/boot/grub/grub.cfg
|
||||||
|
cp ${OUT_DIR}/kernel ${OUT_DIR}/cdrom/boot/kernel.elf
|
||||||
|
grub-mkrescue -o ${OUT_DIR}/cdrom.iso ${OUT_DIR}/cdrom
|
||||||
|
;;
|
||||||
|
esac
|
8
error/Cargo.toml
Normal file
8
error/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "error"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
9
error/src/lib.rs
Normal file
9
error/src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub enum Errno {
|
||||||
|
InvalidArgument,
|
||||||
|
DoesNotExist,
|
||||||
|
NotADirectory,
|
||||||
|
OutOfMemory,
|
||||||
|
}
|
17
etc/aarch64-qemu.json
Normal file
17
etc/aarch64-qemu.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"arch": "aarch64",
|
||||||
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"executables": true,
|
||||||
|
"features": "+strict-align,+neon,+fp-armv8",
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"llvm-target": "aarch64-unknown-none",
|
||||||
|
"max-atomic-width": 128,
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"relocation-model": "static",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"pre-link-args": {
|
||||||
|
"ld.lld": [ "-Tetc/aarch64-qemu.ld" ]
|
||||||
|
}
|
||||||
|
}
|
35
etc/aarch64-qemu.ld
Normal file
35
etc/aarch64-qemu.ld
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
ENTRY(_entry);
|
||||||
|
|
||||||
|
KERNEL_OFFSET = 0xFFFFFF8000000000;
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x40080000 + KERNEL_OFFSET;
|
||||||
|
|
||||||
|
PROVIDE(__kernel_start = .);
|
||||||
|
|
||||||
|
.text : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(.text.boot)
|
||||||
|
*(.text*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.rodata : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(.rodata*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.data : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(.data*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.bss : AT(. - KERNEL_OFFSET) {
|
||||||
|
PROVIDE(__bss_start_phys = . - KERNEL_OFFSET);
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss*)
|
||||||
|
. = ALIGN(4K);
|
||||||
|
PROVIDE(__bss_end_phys = . - KERNEL_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROVIDE(__kernel_end = .);
|
||||||
|
}
|
20
etc/common.sh
Normal file
20
etc/common.sh
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
if [ "$ARCH" = "" ]; then
|
||||||
|
ARCH=aarch64
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $ARCH in
|
||||||
|
aarch64)
|
||||||
|
if [ "$MACH" = "" ]; then
|
||||||
|
MACH=qemu
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
MACH=none
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$PROFILE" = "" ]; then
|
||||||
|
PROFILE=debug
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUT_DIR=target/${ARCH}-${MACH}/${PROFILE}
|
4
etc/gdbrc
Normal file
4
etc/gdbrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
target remote :1234
|
||||||
|
set scheduler-locking on
|
||||||
|
layout src
|
||||||
|
layout regs
|
3
etc/x86_64-none.grub
Normal file
3
etc/x86_64-none.grub
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
menuentry "OS" {
|
||||||
|
multiboot2 /boot/kernel.elf
|
||||||
|
}
|
24
etc/x86_64-none.json
Normal file
24
etc/x86_64-none.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"arch": "x86_64",
|
||||||
|
"cpu": "x86-64",
|
||||||
|
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
|
||||||
|
|
||||||
|
"disable-redzone": true,
|
||||||
|
"executables": true,
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
|
||||||
|
"llvm-target": "x86_64-unknown-linux-gnu",
|
||||||
|
"max-atomic-width": 64,
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
|
||||||
|
"os": "none",
|
||||||
|
|
||||||
|
"pre-link-args": {
|
||||||
|
"ld.lld": [
|
||||||
|
"-Tetc/x86_64-none.ld"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
25
etc/x86_64-none.ld
Normal file
25
etc/x86_64-none.ld
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
ENTRY(_entry);
|
||||||
|
|
||||||
|
KERNEL_OFFSET = 0xFFFFFF8000000000;
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x400000 + KERNEL_OFFSET;
|
||||||
|
|
||||||
|
.text : AT(. - KERNEL_OFFSET) {
|
||||||
|
KEEP(*(.multiboot))
|
||||||
|
*(.text*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(.rodata*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(.data*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : AT(. - KERNEL_OFFSET) {
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss*)
|
||||||
|
}
|
||||||
|
}
|
5
gdb.sh
Executable file
5
gdb.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. etc/common.sh
|
||||||
|
|
||||||
|
gdb-multiarch -x etc/gdbrc target/${ARCH}-${MACH}/${PROFILE}/kernel
|
2
kernel/.cargo/config.toml
Normal file
2
kernel/.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[unstable]
|
||||||
|
build-std = ["core", "compiler_builtins", "alloc"]
|
12
kernel/Cargo.toml
Normal file
12
kernel/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
|
cortex-a = { version = "6.x.x" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
mach_qemu = []
|
26
kernel/src/main.rs
Normal file
26
kernel/src/main.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#![feature(global_asm)]
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic_handler(_pi: &PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_asm!(r#"
|
||||||
|
.section .text._entry
|
||||||
|
.global _entry
|
||||||
|
_entry:
|
||||||
|
mrs x1, mpidr_el1
|
||||||
|
and x1, x1, #3
|
||||||
|
beq 2f
|
||||||
|
1:
|
||||||
|
wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
2:
|
||||||
|
b .
|
||||||
|
"#);
|
36
qemu.sh
Executable file
36
qemu.sh
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. etc/common.sh
|
||||||
|
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
QEMU_OPTS="-chardev id=char0,mux=on,backend=stdio \
|
||||||
|
-s"
|
||||||
|
|
||||||
|
case $ARCH in
|
||||||
|
aarch64)
|
||||||
|
case $MACH in
|
||||||
|
qemu)
|
||||||
|
QEMU_OPTS="$QEMU_OPTS \
|
||||||
|
-M virt,virtualization=on \
|
||||||
|
-m 512 \
|
||||||
|
-serial chardev:char0 \
|
||||||
|
-cpu cortex-a72 \
|
||||||
|
-kernel target/${ARCH}-${MACH}/${PROFILE}/kernel.bin"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
QEMU_OPTS="$QEMU_OPTS \
|
||||||
|
-M q35 \
|
||||||
|
-m 512 \
|
||||||
|
-serial chardev:char0 \
|
||||||
|
-cpu host \
|
||||||
|
-enable-kvm \
|
||||||
|
-cdrom target/${ARCH}-${MACH}/${PROFILE}/cdrom.iso"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
qemu-system-${ARCH} ${QEMU_OPTS} $@
|
3
src/main.rs
Normal file
3
src/main.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user