From d6023980626c6dea3e9de7d2673cef030ef3c327 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 22 Sep 2021 11:42:00 +0300 Subject: [PATCH] Initial commit --- .gitignore | 1 + Cargo.lock | 40 +++++ Cargo.toml | 15 ++ address/Cargo.toml | 9 + address/src/base/mod.rs | 0 address/src/lib.rs | 21 +++ address/src/phys.rs | 177 ++++++++++++++++++ address/src/virt.rs | 364 ++++++++++++++++++++++++++++++++++++++ build.sh | 35 ++++ error/Cargo.toml | 8 + error/src/lib.rs | 9 + etc/aarch64-qemu.json | 17 ++ etc/aarch64-qemu.ld | 35 ++++ etc/common.sh | 20 +++ etc/gdbrc | 4 + etc/x86_64-none.grub | 3 + etc/x86_64-none.json | 24 +++ etc/x86_64-none.ld | 25 +++ gdb.sh | 5 + kernel/.cargo/config.toml | 2 + kernel/Cargo.toml | 12 ++ kernel/src/main.rs | 26 +++ qemu.sh | 36 ++++ src/main.rs | 3 + 24 files changed, 891 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 address/Cargo.toml create mode 100644 address/src/base/mod.rs create mode 100644 address/src/lib.rs create mode 100644 address/src/phys.rs create mode 100644 address/src/virt.rs create mode 100755 build.sh create mode 100644 error/Cargo.toml create mode 100644 error/src/lib.rs create mode 100644 etc/aarch64-qemu.json create mode 100644 etc/aarch64-qemu.ld create mode 100644 etc/common.sh create mode 100644 etc/gdbrc create mode 100644 etc/x86_64-none.grub create mode 100644 etc/x86_64-none.json create mode 100644 etc/x86_64-none.ld create mode 100755 gdb.sh create mode 100644 kernel/.cargo/config.toml create mode 100644 kernel/Cargo.toml create mode 100644 kernel/src/main.rs create mode 100755 qemu.sh create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..7edfb03 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..93d5d57 --- /dev/null +++ b/Cargo.toml @@ -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" +] diff --git a/address/Cargo.toml b/address/Cargo.toml new file mode 100644 index 0000000..73486c9 --- /dev/null +++ b/address/Cargo.toml @@ -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" } diff --git a/address/src/base/mod.rs b/address/src/base/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/address/src/lib.rs b/address/src/lib.rs new file mode 100644 index 0000000..f72152a --- /dev/null +++ b/address/src/lib.rs @@ -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}; diff --git a/address/src/phys.rs b/address/src/phys.rs new file mode 100644 index 0000000..05d9b31 --- /dev/null +++ b/address/src/phys.rs @@ -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> Add for PhysicalAddress { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: A) -> Self { + // Will panic on overflow + Self::from(self.0 + rhs.into()) + } +} +impl> AddAssign for PhysicalAddress { + #[inline(always)] + fn add_assign(&mut self, rhs: A) { + // Will panic on overflow + *self = Self::from(self.0 + rhs.into()); + } +} +impl Sub for PhysicalAddress { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self { + Self::from(self.0 - rhs) + } +} +impl SubAssign for PhysicalAddress { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + *self = Self::from(self.0 - rhs); + } +} + +// Construction +impl From for PhysicalAddress { + fn from(p: usize) -> Self { + Self(p) + } +} + +#[cfg(target_pointer_width = "64")] +impl From 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 const From for VirtualAddress { + fn from(p: PhysicalAddress) -> Self { + VirtualAddress::from(p.0 + T::OFFSET) + } +} + +impl const From for usize { + #[inline(always)] + fn from(p: PhysicalAddress) -> Self { + p.0 as usize + } +} + +#[cfg(target_pointer_width = "64")] +impl From 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, "", self.0) + } +} + +// Step +impl Step for PhysicalAddress { + #[inline] + fn steps_between(_p0: &Self, _p1: &Self) -> Option { + todo!() + } + + #[inline] + fn forward_checked(p: Self, steps: usize) -> Option { + p.0.checked_add(steps).map(Self::from) + } + + #[inline] + fn backward_checked(p: Self, steps: usize) -> Option { + 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::::from(p0), + VirtualAddress::::from(0x9234usize) + ); + } + + #[test] + #[should_panic] + fn test_virt_convert_invalid() { + let p0 = PhysicalAddress::from(0x4321usize); + let _v = VirtualAddress::::from(p0); + } +} diff --git a/address/src/virt.rs b/address/src/virt.rs new file mode 100644 index 0000000..506674e --- /dev/null +++ b/address/src/virt.rs @@ -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(usize, PhantomData); + +// Arithmetic +impl Add for VirtualAddress { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self { + // Will panic on overflow + Self::from(self.0 + rhs) + } +} +impl AddAssign for VirtualAddress { + #[inline(always)] + fn add_assign(&mut self, rhs: usize) { + // Will panic on overflow + *self = Self::from(self.0 + rhs); + } +} +impl Sub for VirtualAddress { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self { + // Will panic on underflow + Self::from(self.0 - rhs) + } +} +impl SubAssign for VirtualAddress { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + // Will panic on underflow + *self = Self::from(self.0 - rhs); + } +} + +// Trivial conversion VirtualAddress -> PhysicalAddress +impl From> for PhysicalAddress { + #[inline(always)] + fn from(virt: VirtualAddress) -> Self { + assert!(virt.0 < T::LIMIT); + PhysicalAddress::from(virt.0 - T::OFFSET) + } +} + +// Formatting +impl fmt::Debug for VirtualAddress { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "<{} {:#018x}>", T::NAME, self.0) + } +} + +impl VirtualAddress { + #[inline(always)] + pub const fn null() -> Self { + Self(0, PhantomData) + } + + pub fn try_subtract(self, p: usize) -> Option { + 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 { + 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(self, count: usize) -> &'static mut [U] { + core::slice::from_raw_parts_mut(self.0 as *mut _, count) + } + + #[inline(always)] + pub fn as_mut_ptr(self) -> *mut U { + self.0 as *mut U + } + + #[inline(always)] + pub fn as_ptr(self) -> *const U { + self.0 as *const U + } + + #[inline(always)] + pub unsafe fn as_mut(self) -> Option<&'static mut U> { + (self.0 as *mut U).as_mut() + } + + #[inline(always)] + pub unsafe fn from_ptr(r: *const U) -> Self { + Self::from(r as usize) + } + + #[inline(always)] + pub unsafe fn from_ref(r: &U) -> Self { + Self(r as *const U as usize, PhantomData) + } +} + +// Step +impl Step for VirtualAddress { + #[inline] + fn steps_between(_p0: &Self, _p1: &Self) -> Option { + todo!() + } + + #[inline] + fn forward_checked(p: Self, steps: usize) -> Option { + p.0.checked_add(steps).map(Self::from) + } + + #[inline] + fn backward_checked(p: Self, steps: usize) -> Option { + p.0.checked_sub(steps).map(Self::from) + } +} + +// Conversion into VirtualAddress +impl const From for VirtualAddress { + #[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 From for VirtualAddress { + #[inline(always)] + fn from(p: u64) -> Self { + Self::from(p as usize) + } +} + +// Conversion from VirtualAddress +impl From> for usize { + #[inline(always)] + fn from(p: VirtualAddress) -> Self { + p.0 + } +} + +#[cfg(target_pointer_width = "64")] +impl From> for u64 { + #[inline(always)] + fn from(p: VirtualAddress) -> 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::::from(i); + } + } + + #[test] + #[should_panic] + fn test_trivial_construct_invalid_0() { + let _v = VirtualAddress::::from(0x1234usize); + } + + #[test] + #[should_panic] + fn test_trivial_construct_invalid_1() { + let _v = VirtualAddress::::from(0xD123usize); + } + + #[test] + fn test_trivial_convert() { + let v0 = VirtualAddress::::from(0x8123usize); + assert_eq!( + PhysicalAddress::from(v0), + PhysicalAddress::from(0x123usize) + ); + } + + #[test] + fn test_add_valid() { + let v0 = VirtualAddress::::from(0x8100usize); + assert_eq!(VirtualAddress::::from(0x8223usize), v0 + 0x123usize); + } + + #[test] + #[should_panic] + fn test_add_overflow() { + let v0 = VirtualAddress::::from(0x8100usize); + let _v = v0 - 0xF123usize; + } + + #[test] + fn test_subtract_valid() { + let v0 = VirtualAddress::::from(0x8100usize); + assert_eq!(VirtualAddress::::from(0x8023usize), v0 - 0xDDusize); + } + + #[test] + #[should_panic] + fn test_subtract_overflow() { + let v0 = VirtualAddress::::from(0x8100usize); + let _v = v0 - 0x1234usize; + } + + #[test] + fn test_try_subtract() { + let v0 = VirtualAddress::::from(0x8100usize); + assert_eq!(v0.try_subtract(0x1234usize), None); + assert_eq!( + v0.try_subtract(0x12usize), + Some(VirtualAddress::::from(0x80EEusize)) + ); + } + + #[test] + fn test_add_assign_valid() { + let mut v0 = VirtualAddress::::from(0x8100usize); + v0 += 0x123usize; + assert_eq!(v0, VirtualAddress::::from(0x8223usize)); + } + + #[test] + fn test_sub_assign_valid() { + let mut v0 = VirtualAddress::::from(0x8321usize); + v0 -= 0x123usize; + assert_eq!(v0, VirtualAddress::::from(0x81FEusize)); + } + + #[test] + #[should_panic] + fn test_sub_assign_overflow() { + let mut v0 = VirtualAddress::::from(0x8321usize); + v0 -= 0x1234usize; + } + + #[test] + #[should_panic] + fn test_add_assign_overflow() { + let mut v0 = VirtualAddress::::from(0x8321usize); + v0 += 0xF234usize; + } + + #[test] + fn test_format() { + let v0 = VirtualAddress::::from(0x8123usize); + assert_eq!(&format!("{:?}", v0), ""); + } + + #[test] + fn test_diff() { + let v0 = VirtualAddress::::from(0x8123usize); + let v1 = VirtualAddress::::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::::from(0usize); + let v1 = VirtualAddress::::from(usize::MAX); + + let _v = VirtualAddress::diff(v0, v1); + } + + #[test] + fn test_step() { + let mut count = 0; + for _ in VirtualAddress::::from(0x8000usize)..VirtualAddress::::from(0x8300usize) { + count += 1; + } + assert_eq!(count, 0x300); + + let mut count = 0; + for _ in (VirtualAddress::::from(0x8000usize)..VirtualAddress::::from(0x8300usize)) + .step_by(0x100) + { + count += 1; + } + assert_eq!(count, 3); + + let mut count = 0; + for _ in + (VirtualAddress::::from(0x8000usize)..VirtualAddress::::from(0x8300usize)).rev() + { + count += 1; + } + assert_eq!(count, 0x300); + + let mut count = 0; + for _ in (VirtualAddress::::from(0x8000usize)..VirtualAddress::::from(0x8300usize)) + .rev() + .step_by(0x100) + { + count += 1; + } + assert_eq!(count, 3); + } +} diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..77bf395 --- /dev/null +++ b/build.sh @@ -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 diff --git a/error/Cargo.toml b/error/Cargo.toml new file mode 100644 index 0000000..31b8188 --- /dev/null +++ b/error/Cargo.toml @@ -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] diff --git a/error/src/lib.rs b/error/src/lib.rs new file mode 100644 index 0000000..e724d08 --- /dev/null +++ b/error/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] + +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum Errno { + InvalidArgument, + DoesNotExist, + NotADirectory, + OutOfMemory, +} diff --git a/etc/aarch64-qemu.json b/etc/aarch64-qemu.json new file mode 100644 index 0000000..98409fc --- /dev/null +++ b/etc/aarch64-qemu.json @@ -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" ] + } +} diff --git a/etc/aarch64-qemu.ld b/etc/aarch64-qemu.ld new file mode 100644 index 0000000..08df6d2 --- /dev/null +++ b/etc/aarch64-qemu.ld @@ -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 = .); +} diff --git a/etc/common.sh b/etc/common.sh new file mode 100644 index 0000000..d5f46c6 --- /dev/null +++ b/etc/common.sh @@ -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} diff --git a/etc/gdbrc b/etc/gdbrc new file mode 100644 index 0000000..a85577f --- /dev/null +++ b/etc/gdbrc @@ -0,0 +1,4 @@ +target remote :1234 +set scheduler-locking on +layout src +layout regs diff --git a/etc/x86_64-none.grub b/etc/x86_64-none.grub new file mode 100644 index 0000000..8c32065 --- /dev/null +++ b/etc/x86_64-none.grub @@ -0,0 +1,3 @@ +menuentry "OS" { + multiboot2 /boot/kernel.elf +} diff --git a/etc/x86_64-none.json b/etc/x86_64-none.json new file mode 100644 index 0000000..6681fa4 --- /dev/null +++ b/etc/x86_64-none.json @@ -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" + ] + } +} diff --git a/etc/x86_64-none.ld b/etc/x86_64-none.ld new file mode 100644 index 0000000..fe364f1 --- /dev/null +++ b/etc/x86_64-none.ld @@ -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*) + } +} diff --git a/gdb.sh b/gdb.sh new file mode 100755 index 0000000..f6a8569 --- /dev/null +++ b/gdb.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. etc/common.sh + +gdb-multiarch -x etc/gdbrc target/${ARCH}-${MACH}/${PROFILE}/kernel diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml new file mode 100644 index 0000000..4be9155 --- /dev/null +++ b/kernel/.cargo/config.toml @@ -0,0 +1,2 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml new file mode 100644 index 0000000..b3089bf --- /dev/null +++ b/kernel/Cargo.toml @@ -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 = [] diff --git a/kernel/src/main.rs b/kernel/src/main.rs new file mode 100644 index 0000000..868738f --- /dev/null +++ b/kernel/src/main.rs @@ -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 . +"#); diff --git a/qemu.sh b/qemu.sh new file mode 100755 index 0000000..4c7ada9 --- /dev/null +++ b/qemu.sh @@ -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} $@ diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}